Skip to content

Commit

Permalink
Merge pull request #6 from mgdm/tls
Browse files Browse the repository at this point in the history
Add basics of TLS support
  • Loading branch information
mgdm committed Dec 5, 2013
2 parents bbab605 + 74647c8 commit c9c9055
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 6 deletions.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ This is the actual Mosquitto client.

1. [__construct](#__construct) - create a new client
1. [setCredentials](#setcredentials) - set the credentials to use on connection
1. [setTlsCertificates](#settlscertificates) - set the TLS certificate sources
1. [setTlsInsecure](#settlsinsecure) - Set verification of the server hostname
in TLS certificates
1. [setTlsOptions](#settlsoptions) - Set advanced TLS options
1. [setTlsPSK](#settlspsk) - Configure the client for pre-shared-key based TLS
support.
1. [setWill](#setwill) - set the client will, to be delivered if disconnected
uncleanly
1. [clearWill](#clearwill) - clear a previously-set will
Expand Down Expand Up @@ -83,6 +89,56 @@ called before connect().
| Username | string | Username to supply to the broker |
| Password | string | Password to supply to the broker |

#### setTlsCertificates

Configure the client for certificate based SSL/TLS support. Must be called
before connect(). Cannot be used in conjunction with setTlsPSK().

Define the Certificate Authority certificates to be trusted (ie. the server
certificate must be signed with one of these certificates) using cafile.
If the server you are connecting to requires clients to provide a certificate,
define certfile and keyfile with your client certificate and private key. If
your private key is encrypted, provide the password as the fourth parameter, or
you will have to enter the password at the command line.

| Parameter | Type | Description |
| --- | --- | ---- |
| capath | string | Path to the PEM encoded trusted CA certificate files, or to a directory containing them |
| certfile | string | Path to the PEM encoded certificate file for this client. Optional. |
| keyfile | string | Path to a file containing the PEM encoded private key for this client. Required if certfile is set. |
| password | string | The password for the keyfile, if it is encrypted. If null, the password will be asked for on the command line. |

#### setTlsInsecure

Configure verification of the server hostname in the server certificate. If
value is set to true, it is impossible to guarantee that the host you are
connecting to is not impersonating your server. Do not use this function in
a real system. Must be called before connect().

| Parameter | Type | Description |
| --- | --- | ---- |
| value | boolean | If set to false, the default, certificate hostname checking is performed. If set to true, no hostname checking is performed and the connection is insecure. |

#### setTlsOptions

Set advanced SSL/TLS options. Must be called before connect().

| Parameter | Type | Description |
| --- | --- | ---- |
| certReqs | int | Whether or not to verify the server. Can be Mosquitto\Client::SSL_VERIFY_NONE, to disable certificate verification, or Mosquitto\Client::SSL_VERIFY_PEER (the default), to verify the server certificate. |
| tlsVersion | string | The TLS version to use. If NULL, a default is used. The default value depends on the version of OpenSSL the library was compiled against. Available options on OpenSSL >= 1.0.1 are 'tlsv1.2', 'tlsv1.1' and 'tlsv1'. |
| cipers | string | A string describing the ciphers available for use. See the `openssl ciphers` tool for more information. If NULL, the default set will be used. |

#### setTlsPSK

Configure the client for pre-shared-key based TLS support. Must be called before connect(). Cannot be used in conjunction with setTlsCertificates.

| Parameter | Type | Description |
| --- | --- | ---- |
| psk | string | The pre-shared key in hex format with no leading "0x".
| identity | string " The identity of this client. May be used as the username depending on server settings. |
| cipers | string | A string describing the ciphers available for use. See the `openssl ciphers` tool for more information. If NULL, the default set will be used. |

#### setWill

Set the client "last will and testament", which will be sent on an unclean
Expand Down
154 changes: 148 additions & 6 deletions mosquitto.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "zend_variables.h"
#include "zend_exceptions.h"
#include "zend_API.h"
#include "ext/standard/php_filestat.h"
#include "ext/standard/info.h"
#include "php_mosquitto.h"

Expand All @@ -17,6 +18,7 @@ zend_object_handlers mosquitto_std_object_handlers;
ZEND_DECLARE_MODULE_GLOBALS(mosquitto)

static inline mosquitto_client_object *mosquitto_client_object_get(zval *zobj TSRMLS_DC);
static int php_mosquitto_pw_callback(char *buf, int size, int rwflag, void *userdata);

/* {{{ Arginfo */

Expand Down Expand Up @@ -112,6 +114,131 @@ PHP_METHOD(Mosquitto_Client, __construct)
}
/* }}} */

/* {{{ Mosquitto\Client::setTlsCertificates() */
PHP_METHOD(Mosquitto_Client, setTlsCertificates)
{
mosquitto_client_object *object;
char *ca_path = NULL, *cert_path = NULL, *key_path = NULL, *key_pw = NULL;
int ca_path_len = 0, cert_path_len = 0, key_path_len = 0, key_pw_len, retval = 0;
zval *stat;
zend_bool is_dir = 0;
int (*pw_callback)(char *, int, int, void *) = NULL;

PHP_MOSQUITTO_ERROR_HANDLING();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|s!s!s!",
&ca_path, &ca_path_len,
&cert_path, &cert_path_len,
&key_path, &key_path_len,
&key_pw, &key_pw_len) == FAILURE) {
PHP_MOSQUITTO_RESTORE_ERRORS();
return;
}

if ((php_check_open_basedir(ca_path TSRMLS_CC) < 0) ||
(php_check_open_basedir(cert_path TSRMLS_CC) < 0) ||
(php_check_open_basedir(key_path TSRMLS_CC) < 0))
{
PHP_MOSQUITTO_RESTORE_ERRORS();
return;
}

PHP_MOSQUITTO_RESTORE_ERRORS();

object = (mosquitto_client_object *) zend_object_store_get_object(getThis() TSRMLS_CC);

php_stat(ca_path, ca_path_len, FS_IS_DIR, stat TSRMLS_CC);
is_dir = Z_BVAL_P(stat);
zval_dtor(stat);

if (key_pw != NULL) {
pw_callback = php_mosquitto_pw_callback;
MQTTG(client_key) = estrdup(key_pw);
MQTTG(client_key_len) = key_pw_len;
}

if (is_dir) {
retval = mosquitto_tls_set(object->client, NULL, ca_path, cert_path, key_path, pw_callback);
} else {
retval = mosquitto_tls_set(object->client, ca_path, NULL, cert_path, key_path, pw_callback);
}

php_mosquitto_handle_errno(retval, errno TSRMLS_CC);
}
/* }}} */

/* {{{ Mosquitto\Client::setTlsInsecure() */
PHP_METHOD(Mosquitto_Client, setTlsInsecure)
{
mosquitto_client_object *object;
zend_bool value = 0;
int retval = 0;

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

object = (mosquitto_client_object *) zend_object_store_get_object(getThis() TSRMLS_CC);

retval = mosquitto_tls_insecure_set(object->client, value);

php_mosquitto_handle_errno(retval, errno TSRMLS_CC);
}
/* }}} */

/* {{{ Mosquitto\Client::setTlsOptions() */
PHP_METHOD(Mosquitto_Client, setTlsOptions)
{
mosquitto_client_object *object;
char *tls_version = NULL, *ciphers = NULL;
int tls_version_len = 0, ciphers_len = 0, retval = 0;
zend_bool verify_peer = 0;

PHP_MOSQUITTO_ERROR_HANDLING();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "bs!s!",
&verify_peer,
&tls_version, &tls_version_len,
&ciphers, &ciphers_len
) == FAILURE) {
PHP_MOSQUITTO_RESTORE_ERRORS();
return;
}
PHP_MOSQUITTO_RESTORE_ERRORS();

object = (mosquitto_client_object *) zend_object_store_get_object(getThis() TSRMLS_CC);

retval = mosquitto_tls_opts_set(object->client, verify_peer, tls_version, ciphers);

php_mosquitto_handle_errno(retval, errno TSRMLS_CC);
}
/* }}} */

/* {{{ Mosquitto\Client::setTlsPSK() */
PHP_METHOD(Mosquitto_Client, setTlsPSK)
{
mosquitto_client_object *object;
char *psk = NULL, *identity = NULL, *ciphers = NULL;
int psk_len = 0, identity_len = 0, ciphers_len = 0, retval = 0;

PHP_MOSQUITTO_ERROR_HANDLING();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!s!|s!",
&psk, &psk_len, &identity, &identity_len, &ciphers, &ciphers_len
) == FAILURE) {
PHP_MOSQUITTO_RESTORE_ERRORS();
return;
}
PHP_MOSQUITTO_RESTORE_ERRORS();

object = (mosquitto_client_object *) zend_object_store_get_object(getThis() TSRMLS_CC);

retval = mosquitto_tls_psk_set(object->client, psk, identity, ciphers);

php_mosquitto_handle_errno(retval, errno TSRMLS_CC);
}
/* }}} */

/* {{{ Mosquitto\Client::setCredentials() */
PHP_METHOD(Mosquitto_Client, setCredentials)
{
Expand Down Expand Up @@ -951,6 +1078,14 @@ PHP_MOSQUITTO_API void php_mosquitto_unsubscribe_callback(struct mosquitto *mosq
}
}

static int php_mosquitto_pw_callback(char *buf, int size, int rwflag, void *userdata) {
TSRMLS_FETCH();

strncpy(buf, MQTTG(client_key), size);
efree(MQTTG(client_key));
return MQTTG(client_key_len);
}

/* {{{ mosquitto_client_methods */
const zend_function_entry mosquitto_client_methods[] = {
PHP_ME(Mosquitto_Client, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
Expand All @@ -961,6 +1096,10 @@ const zend_function_entry mosquitto_client_methods[] = {
PHP_ME(Mosquitto_Client, onUnsubscribe, Mosquitto_Client_callback_args, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, onMessage, Mosquitto_Client_callback_args, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, getSocket, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setTlsCertificates, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setTlsInsecure, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setTlsOptions, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setTlsPSK, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setCredentials, Mosquitto_Client_setCredentials_args, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setWill, Mosquitto_Client_setWill_args, ZEND_ACC_PUBLIC)
PHP_ME(Mosquitto_Client, setReconnectDelay, Mosquitto_Client_setReconnectDelay_args, ZEND_ACC_PUBLIC)
Expand Down Expand Up @@ -1024,15 +1163,18 @@ PHP_MINIT_FUNCTION(mosquitto)
mosquitto_ce_exception = zend_register_internal_class_ex(&exception_ce,
zend_exception_get_default(TSRMLS_C), "Exception" TSRMLS_CC);

#define REGISTER_MOSQUITTO_LOG_LONG_CONST(const_name, value) \
#define REGISTER_MOSQUITTO_LONG_CONST(const_name, value) \
zend_declare_class_constant_long(mosquitto_ce_client, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC); \
REGISTER_LONG_CONSTANT(#value, value, CONST_CS | CONST_PERSISTENT);

REGISTER_MOSQUITTO_LOG_LONG_CONST("LOG_INFO", MOSQ_LOG_INFO);
REGISTER_MOSQUITTO_LOG_LONG_CONST("LOG_NOTICE", MOSQ_LOG_NOTICE);
REGISTER_MOSQUITTO_LOG_LONG_CONST("LOG_WARNING", MOSQ_LOG_WARNING);
REGISTER_MOSQUITTO_LOG_LONG_CONST("LOG_ERR", MOSQ_LOG_ERR);
REGISTER_MOSQUITTO_LOG_LONG_CONST("LOG_DEBUG", MOSQ_LOG_DEBUG);
REGISTER_MOSQUITTO_LONG_CONST("LOG_INFO", MOSQ_LOG_INFO);
REGISTER_MOSQUITTO_LONG_CONST("LOG_NOTICE", MOSQ_LOG_NOTICE);
REGISTER_MOSQUITTO_LONG_CONST("LOG_WARNING", MOSQ_LOG_WARNING);
REGISTER_MOSQUITTO_LONG_CONST("LOG_ERR", MOSQ_LOG_ERR);
REGISTER_MOSQUITTO_LONG_CONST("LOG_DEBUG", MOSQ_LOG_DEBUG);

REGISTER_MOSQUITTO_LONG_CONST("SSL_VERIFY_NONE", 0);
REGISTER_MOSQUITTO_LONG_CONST("SSL_VERIFY_PEER", 1);

mosquitto_lib_init();

Expand Down
1 change: 1 addition & 0 deletions php_mosquitto.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ static int php_mosquitto_message_write_##name(mosquitto_message_object *mosquitt

ZEND_BEGIN_MODULE_GLOBALS(mosquitto)
char *client_key;
int client_key_len;
zend_object_handlers mosquitto_std_object_handlers;
zend_error_handling mosquitto_original_error_handling;
ZEND_END_MODULE_GLOBALS(mosquitto)
Expand Down

0 comments on commit c9c9055

Please sign in to comment.