Skip to content

Commit

Permalink
Add SSL connection support
Browse files Browse the repository at this point in the history
  • Loading branch information
pinepain committed Apr 27, 2016
1 parent 913dc02 commit 83defa1
Show file tree
Hide file tree
Showing 41 changed files with 8,911 additions and 153 deletions.
4 changes: 4 additions & 0 deletions amqp.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ PHP_INI_BEGIN()
PHP_INI_ENTRY("amqp.channel_max", DEFAULT_CHANNEL_MAX, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.frame_max", DEFAULT_FRAME_MAX, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.heartbeat", DEFAULT_HEARTBEAT, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.cacert", DEFAULT_CACERT, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.cert", DEFAULT_CERT, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.key", DEFAULT_KEY, PHP_INI_ALL, NULL)
PHP_INI_ENTRY("amqp.verify", DEFAULT_VERIFY, PHP_INI_ALL, NULL)
PHP_INI_END()

ZEND_DECLARE_MODULE_GLOBALS(amqp);
Expand Down
182 changes: 178 additions & 4 deletions amqp_connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,27 @@ zend_class_entry *amqp_connection_class_entry;

zend_object_handlers amqp_connection_object_handlers;

#define PHP_AMQP_EXTRACT_CONNECTION_STR(name) \
zdata = NULL; \
if (ini_arr && PHP5to7_ZEND_HASH_FIND(HASH_OF(ini_arr), (name), sizeof(name), zdata)) { \
convert_to_string(PHP5to7_MAYBE_DEREF(zdata)); \
} \
if (zdata && Z_STRLEN_P(PHP5to7_MAYBE_DEREF(zdata)) > 0) { \
zend_update_property_string(this_ce, getThis(), ZEND_STRL(name), Z_STRVAL_P(PHP5to7_MAYBE_DEREF(zdata)) TSRMLS_CC); \
} else { \
zend_update_property_string(this_ce, getThis(), ZEND_STRL(name), INI_STR("amqp." name) TSRMLS_CC); \
}

#define PHP_AMQP_EXTRACT_CONNECTION_BOOL(name) \
zdata = NULL; \
if (ini_arr && PHP5to7_ZEND_HASH_FIND(HASH_OF(ini_arr), (name), sizeof(name), zdata)) { \
convert_to_long(PHP5to7_MAYBE_DEREF(zdata)); \
} \
if (zdata) { \
zend_update_property_bool(this_ce, getThis(), ZEND_STRL(name), Z_LVAL_P(PHP5to7_MAYBE_DEREF(zdata)) TSRMLS_CC); \
} else { \
zend_update_property_bool(this_ce, getThis(), ZEND_STRL(name), INI_INT("amqp." name) TSRMLS_CC); \
}

static int php_amqp_connection_resource_deleter(PHP5to7_zend_resource_le_t *el, amqp_connection_resource *connection_resource TSRMLS_DC)
{
Expand All @@ -74,15 +95,18 @@ static int php_amqp_connection_resource_deleter(PHP5to7_zend_resource_le_t *el,
static PHP5to7_param_str_len_type_t php_amqp_get_connection_hash(amqp_connection_params *params, char **hash) {
return spprintf(hash,
0,
"amqp_conn_res_h:%s_p:%d_v:%s_l:%s_p:%s_f:%d_c:%d_h:%d",
"amqp_conn_res_h:%s_p:%d_v:%s_l:%s_p:%s_f:%d_c:%d_h:%d_cacert:%s_cert:%s_key:%s",
params->host,
params->port,
params->vhost,
params->login,
params->password,
params->frame_max,
params->channel_max,
params->heartbeat
params->heartbeat,
params->cacert,
params->cert,
params->key
);
}

Expand Down Expand Up @@ -160,7 +184,10 @@ int php_amqp_connect(amqp_connection_object *connection, zend_bool persistent, I
connection_params.read_timeout = PHP_AMQP_READ_THIS_PROP_DOUBLE("read_timeout");
connection_params.write_timeout = PHP_AMQP_READ_THIS_PROP_DOUBLE("write_timeout");
connection_params.connect_timeout = PHP_AMQP_READ_THIS_PROP_DOUBLE("connect_timeout");

connection_params.cacert = PHP_AMQP_READ_THIS_PROP_STRLEN("cacert") ? PHP_AMQP_READ_THIS_PROP_STR("cacert") : NULL;
connection_params.cert = PHP_AMQP_READ_THIS_PROP_STRLEN("cert") ? PHP_AMQP_READ_THIS_PROP_STR("cert") : NULL;
connection_params.key = PHP_AMQP_READ_THIS_PROP_STRLEN("key") ? PHP_AMQP_READ_THIS_PROP_STR("key") : NULL;
connection_params.verify = (int) PHP_AMQP_READ_THIS_PROP_BOOL("verify");

if (persistent) {
PHP5to7_zend_resource_store_t *le = PHP5to7_ZEND_RESOURCE_EMPTY;
Expand Down Expand Up @@ -483,6 +510,11 @@ static PHP_METHOD(amqp_connection_class, __construct)
}
}

PHP_AMQP_EXTRACT_CONNECTION_STR("cacert");
PHP_AMQP_EXTRACT_CONNECTION_STR("key");
PHP_AMQP_EXTRACT_CONNECTION_STR("cert");

PHP_AMQP_EXTRACT_CONNECTION_BOOL("verify");
}
/* }}} */

Expand Down Expand Up @@ -1035,7 +1067,7 @@ static PHP_METHOD(amqp_connection_class, getUsedChannels)

/* {{{ proto amqp::getMaxChannels()
Get max supported channels number per connection */
static PHP_METHOD(amqp_connection_class, getMaxChannels)
PHP_METHOD(amqp_connection_class, getMaxChannels)
{
PHP5to7_READ_PROP_RV_PARAM_DECL;
amqp_connection_object *connection;
Expand Down Expand Up @@ -1113,6 +1145,103 @@ static PHP_METHOD(amqp_connection_class, isPersistent)
/* }}} */


/* {{{ proto amqp::getCACert() */
static PHP_METHOD(amqp_connection_class, getCACert)
{
PHP5to7_READ_PROP_RV_PARAM_DECL;
PHP_AMQP_NOPARAMS();
PHP_AMQP_RETURN_THIS_PROP("cacert");
}
/* }}} */

/* {{{ proto amqp::setCACert(string cacert) */
static PHP_METHOD(amqp_connection_class, setCACert)
{
char *str = NULL; PHP5to7_param_str_len_type_t str_len = 0;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}

zend_update_property_stringl(this_ce, getThis(), ZEND_STRL("cacert"), str, str_len TSRMLS_CC);

RETURN_TRUE;
}
/* }}} */

/* {{{ proto amqp::getCert() */
static PHP_METHOD(amqp_connection_class, getCert)
{
PHP5to7_READ_PROP_RV_PARAM_DECL;
PHP_AMQP_NOPARAMS();
PHP_AMQP_RETURN_THIS_PROP("cert");
}
/* }}} */

/* {{{ proto amqp::setCert(string cert) */
static PHP_METHOD(amqp_connection_class, setCert)
{
char *str = NULL; PHP5to7_param_str_len_type_t str_len = 0;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}

zend_update_property_stringl(this_ce, getThis(), ZEND_STRL("cert"), str, str_len TSRMLS_CC);

RETURN_TRUE;
}
/* }}} */

/* {{{ proto amqp::getKey() */
static PHP_METHOD(amqp_connection_class, getKey)
{
PHP5to7_READ_PROP_RV_PARAM_DECL;
PHP_AMQP_NOPARAMS();
PHP_AMQP_RETURN_THIS_PROP("key");
}
/* }}} */

/* {{{ proto amqp::setKey(string key) */
static PHP_METHOD(amqp_connection_class, setKey)
{
char *str = NULL; PHP5to7_param_str_len_type_t str_len = 0;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}

zend_update_property_stringl(this_ce, getThis(), ZEND_STRL("key"), str, str_len TSRMLS_CC);

RETURN_TRUE;
}
/* }}} */


/* {{{ proto amqp::getVerify() */
static PHP_METHOD(amqp_connection_class, getVerify)
{
PHP5to7_READ_PROP_RV_PARAM_DECL;
PHP_AMQP_NOPARAMS();
PHP_AMQP_RETURN_THIS_PROP("verify");
}
/* }}} */

/* {{{ proto amqp::setVerify(bool verify) */
static PHP_METHOD(amqp_connection_class, setVerify)
{
zend_bool verify = 1;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &verify) == FAILURE) {
return;
}

zend_update_property_bool(this_ce, getThis(), ZEND_STRL("verify"), verify TSRMLS_CC);

RETURN_TRUE;
}
/* }}} */

/* amqp_connection_class ARG_INFO definition */
ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class__construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_ARG_ARRAY_INFO(0, credentials, 0)
Expand Down Expand Up @@ -1210,6 +1339,34 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_isPersistent, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_getCACert, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_setCACert, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, cacert)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_getCert, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_setCert, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, cert)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_getKey, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_setKey, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, key)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_getVerify, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_connection_class_setVerify, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
ZEND_ARG_INFO(0, verify)
ZEND_END_ARG_INFO()


zend_function_entry amqp_connection_class_functions[] = {
PHP_ME(amqp_connection_class, __construct, arginfo_amqp_connection_class__construct, ZEND_ACC_PUBLIC)
Expand Down Expand Up @@ -1251,6 +1408,18 @@ zend_function_entry amqp_connection_class_functions[] = {
PHP_ME(amqp_connection_class, getHeartbeatInterval, arginfo_amqp_connection_class_getHeartbeatInterval, ZEND_ACC_PUBLIC)
PHP_ME(amqp_connection_class, getMaxFrameSize, arginfo_amqp_connection_class_getMaxFrameSize, ZEND_ACC_PUBLIC)

PHP_ME(amqp_connection_class, getCACert, arginfo_amqp_connection_class_getCACert, ZEND_ACC_PUBLIC)
PHP_ME(amqp_connection_class, setCACert, arginfo_amqp_connection_class_setCACert, ZEND_ACC_PUBLIC)

PHP_ME(amqp_connection_class, getCert, arginfo_amqp_connection_class_getCert, ZEND_ACC_PUBLIC)
PHP_ME(amqp_connection_class, setCert, arginfo_amqp_connection_class_setCert, ZEND_ACC_PUBLIC)

PHP_ME(amqp_connection_class, getKey, arginfo_amqp_connection_class_getKey, ZEND_ACC_PUBLIC)
PHP_ME(amqp_connection_class, setKey, arginfo_amqp_connection_class_setKey, ZEND_ACC_PUBLIC)

PHP_ME(amqp_connection_class, getVerify, arginfo_amqp_connection_class_getVerify, ZEND_ACC_PUBLIC)
PHP_ME(amqp_connection_class, setVerify, arginfo_amqp_connection_class_setVerify, ZEND_ACC_PUBLIC)

{NULL, NULL, NULL}
};

Expand All @@ -1277,6 +1446,11 @@ PHP_MINIT_FUNCTION(amqp_connection)
zend_declare_property_null(this_ce, ZEND_STRL("frame_max"), ZEND_ACC_PRIVATE TSRMLS_CC);
zend_declare_property_null(this_ce, ZEND_STRL("heartbeat"), ZEND_ACC_PRIVATE TSRMLS_CC);

zend_declare_property_null(this_ce, ZEND_STRL("cacert"), ZEND_ACC_PRIVATE TSRMLS_CC);
zend_declare_property_null(this_ce, ZEND_STRL("key"), ZEND_ACC_PRIVATE TSRMLS_CC);
zend_declare_property_null(this_ce, ZEND_STRL("cert"), ZEND_ACC_PRIVATE TSRMLS_CC);
zend_declare_property_null(this_ce, ZEND_STRL("verify"), ZEND_ACC_PRIVATE TSRMLS_CC);

#if PHP_MAJOR_VERSION >=7
memcpy(&amqp_connection_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));

Expand Down
40 changes: 39 additions & 1 deletion amqp_connection_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <amqp.h>
#include <amqp_tcp_socket.h>
#include <amqp_framing.h>
#include <amqp_ssl_socket.h>

#ifdef PHP_WIN32
# include "win32/unistd.h"
Expand Down Expand Up @@ -375,7 +376,44 @@ amqp_connection_resource *connection_resource_constructor(amqp_connection_params
resource->connection_state = amqp_new_connection();

/* Create socket object */
resource->socket = amqp_tcp_socket_new(resource->connection_state);
if (params->cacert) {
resource->socket = amqp_ssl_socket_new(resource->connection_state);

if (!resource->socket) {
zend_throw_exception(amqp_connection_exception_class_entry, "Socket error: could not create SSL socket.", 0 TSRMLS_CC);

return NULL;
}
} else {
resource->socket = amqp_tcp_socket_new(resource->connection_state);

if (!resource->socket) {
zend_throw_exception(amqp_connection_exception_class_entry, "Socket error: could not create socket.", 0 TSRMLS_CC);

return NULL;
}
}

if (params->cacert && amqp_ssl_socket_set_cacert(resource->socket, params->cacert)) {
zend_throw_exception(amqp_connection_exception_class_entry, "Socket error: could not set CA certificate.", 0 TSRMLS_CC);

return NULL;
}

if (params->cacert) {
#if AMQP_VERSION_MAJOR * 100 + AMQP_VERSION_MINOR * 10 + AMQP_VERSION_PATCH >= 80
amqp_ssl_socket_set_verify_peer(resource->socket, params->verify);
amqp_ssl_socket_set_verify_hostname(resource->socket, params->verify);
#else
amqp_ssl_socket_set_verify(resource->socket, params->verify);
#endif
}

if (params->cert && params->key && amqp_ssl_socket_set_key(resource->socket, params->cert, params->key)) {
zend_throw_exception(amqp_connection_exception_class_entry, "Socket error: could not setting client cert.", 0 TSRMLS_CC);

return NULL;
}

if (params->connect_timeout > 0) {
tv.tv_sec = (long int) params->connect_timeout;
Expand Down
4 changes: 4 additions & 0 deletions amqp_connection_resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ typedef struct _amqp_connection_params {
double read_timeout;
double write_timeout;
double connect_timeout;
char *cacert;
char *cert;
char *key;
int verify;
} amqp_connection_params;

/* Figure out what's going on connection and handle protocol exceptions, if any */
Expand Down
3 changes: 2 additions & 1 deletion package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ http://pear.php.net/dtd/package-2.0.xsd">
<api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<release>beta</release>
<api>stable</api>
</stability>
<license uri="http://www.php.net/license">PHP License</license>
<notes><![CDATA[
* Support for server method handling: confirms (publisher acknowledgments) and basic.return (Bogdan Padalko)
* Add SSL connection support (Bogdan Padalko)
For a complete list of changes see:
https://github.com/pdezwart/php-amqp/compare/v1.7.0...v1.8.0
Expand Down
4 changes: 4 additions & 0 deletions php_amqp.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ struct _amqp_connection_object {
#define DEFAULT_CHANNEL_MAX PHP_AMQP_STRINGIFY(PHP_AMQP_MAX_CHANNELS)
#define DEFAULT_FRAME_MAX PHP_AMQP_STRINGIFY(PHP_AMQP_DEFAULT_FRAME_MAX)
#define DEFAULT_HEARTBEAT PHP_AMQP_STRINGIFY(PHP_AMQP_DEFAULT_HEARTBEAT)
#define DEFAULT_CACERT ""
#define DEFAULT_CERT ""
#define DEFAULT_KEY ""
#define DEFAULT_VERIFY "1"


#define IS_PASSIVE(bitmask) (AMQP_PASSIVE & (bitmask)) ? 1 : 0
Expand Down
8 changes: 8 additions & 0 deletions provision/rabbitmq.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
%% including the option to control the choice of interface.
%%
%% {ssl_listeners, [5671]},
{ssl_listeners, [5671]},
{ssl_options, [{cacertfile,"/home/vagrant/php-amqp/provision/test_certs/testca/cacert.pem"},
{certfile,"/home/vagrant/php-amqp/provision/test_certs/server/cert.pem"},
{keyfile,"/home/vagrant/php-amqp/provision/test_certs/server/key.pem"},
%% {verify,verify_peer},
{verify,verify_none},
{fail_if_no_peer_cert,false}
]},

%% Maximum time for AMQP 0-8/0-9/0-9-1 handshake (after socket connection
%% and SSL handshake), in milliseconds.
Expand Down
Loading

0 comments on commit 83defa1

Please sign in to comment.