Update: indivisual client assigns TLS connection by clients.conf file.

BugFix: TLS certificate required connection error

Signed-off-by: tomoaki <tomoaki@tomy-tech.com>
This commit is contained in:
tomoaki
2016-09-02 10:24:58 +09:00
parent 039e063c8b
commit 2537dd76dd
20 changed files with 352 additions and 239 deletions

View File

@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <sys/socket.h>
#include <error.h>
#include <regex>
#include "Network.h"
#include "MQTTSNGWDefines.h"
@@ -232,54 +233,27 @@ int TCPStack::getSock()
=======================================*/
int Network::_numOfInstance = 0;
SSL_CTX* Network::_ctx = 0;
SSL_SESSION* Network::_session = 0;
Network::Network(bool secure) :
TCPStack()
{
char error[256];
if (secure)
{
_numOfInstance++;
if (_ctx == 0)
{
SSL_load_error_strings();
SSL_library_init();
_ctx = SSL_CTX_new(TLSv1_2_client_method());
if (_ctx == 0)
{
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
WRITELOG("SSL_CTX_new() %s\n", error);
throw Exception( ERR_get_error(), "Network can't create SSL context.");
}
if (!SSL_CTX_load_verify_locations(_ctx, 0, MQTTSNGW_TLS_CA_DIR))
{
ERR_error_string_n(ERR_get_error(), error, sizeof(error));
WRITELOG("SSL_CTX_load_verify_locations() %s\n", error);
throw Exception( ERR_get_error(), "Network can't load CA_LIST.");
}
}
}
_ssl = 0;
_disconReq = false;
_secureFlg = secure;
_busy = false;
_session = 0;
_sslValid = false;
}
Network::~Network()
{
if (_secureFlg)
{
_numOfInstance--;
}
if (_ssl)
{
SSL_free(_ssl);
_numOfInstance--;
}
if (_session && _numOfInstance == 0)
if (_session )
{
SSL_SESSION_free(_session);
_session = 0;
}
if (_ctx && _numOfInstance == 0)
{
@@ -289,78 +263,172 @@ Network::~Network()
}
}
bool Network::connect(const char* host, const char* service)
bool Network::connect(const char* host, const char* port)
{
if (_secureFlg)
{
return false;
}
if (getSock() == 0)
{
if (!TCPStack::connect(host, port))
{
return false;
}
}
return true;
}
bool Network::connect(const char* host, const char* port, const char* caPath, const char* caFile, const char* cert, const char* prvkey)
{
char errmsg[256];
int rc = 0;
char peer_CN[256];
SSL_SESSION* sess = 0;
X509* peer;
int rc = 0;
if (isValid())
{
return false;
}
if (!TCPStack::connect(host, service))
{
return false;
}
if (!_secureFlg)
{
return true;
WRITELOG("TLS is not required.\n");
return false;
}
SSL* ssl = SSL_new(_ctx);
if (ssl == 0)
if (_ctx == 0)
{
SSL_load_error_strings();
SSL_library_init();
_ctx = SSL_CTX_new(TLS_client_method());
if (_ctx == 0)
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_CTX_new() %s\n", errmsg);
return false;
}
if (!SSL_CTX_load_verify_locations(_ctx, caFile, caPath))
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_CTX_load_verify_locations() %s\n", errmsg);
return false;
}
}
if (!_sslValid)
{
if ( !TCPStack::connect(host, port) )
{
return false;
}
/*
if ( _ssl )
{
if (!SSL_set_fd(_ssl, getSock()))
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_set_fd() %s\n", errmsg);
SSL_free(_ssl);
}
else
{
_sslValid = true;
return true;
}
}
*/
}
_ssl = SSL_new(_ctx);
if (_ssl == 0)
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_new() %s\n", errmsg);
return false;
}
rc = SSL_set_fd(ssl, TCPStack::getSock());
if (rc == 0)
if (!SSL_set_fd(_ssl, getSock()))
{
SSL_free(ssl);
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_set_fd() %s\n", errmsg);
SSL_free(_ssl);
}
SSL_set_options(_ssl, SSL_OP_NO_TICKET);
if ( cert )
{
if ( SSL_use_certificate_file(_ssl, cert, SSL_FILETYPE_PEM) <= 0 )
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_use_certificate_file() %s %s\n", cert, errmsg);
SSL_free(_ssl);
_ssl = 0;
return false;
}
}
if ( prvkey )
{
if ( SSL_use_PrivateKey_file(_ssl, prvkey, SSL_FILETYPE_PEM) <= 0 )
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_use_PrivateKey_file() %s %s\n", prvkey, errmsg);
SSL_free(_ssl);
_ssl = 0;
return false;
}
}
if (!SSL_set_fd(_ssl, TCPStack::getSock()))
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_set_fd() %s\n", errmsg);
SSL_free(_ssl);
_ssl = 0;
return false;
}
if (_session)
{
rc = SSL_set_session(ssl, sess);
rc = SSL_set_session(_ssl, _session);
}
else
{
rc = SSL_connect(ssl);
}
if (rc != 1)
if (SSL_connect(_ssl) != 1)
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("SSL_connect() %s\n", errmsg);
SSL_free(ssl);
SSL_free(_ssl);
_ssl = 0;
return false;
}
if (SSL_get_verify_result(ssl) != X509_V_OK)
if ( (rc = SSL_get_verify_result(_ssl)) != X509_V_OK)
{
WRITELOG("SSL_get_verify_result() error: Certificate doesn't verify.\n");
SSL_free(ssl);
WRITELOG("SSL_get_verify_result() error: %s.\n", X509_verify_cert_error_string(rc));
SSL_free(_ssl);
_ssl = 0;
return false;
}
peer = SSL_get_peer_certificate(ssl);
X509* peer = SSL_get_peer_certificate(_ssl);
X509_NAME_get_text_by_NID(X509_get_subject_name(peer), NID_commonName, peer_CN, 256);
if (strcasecmp(peer_CN, host))
char* pos = peer_CN;
if ( *pos == '*')
{
WRITELOG("SSL_get_peer_certificate() error: Broker dosen't much host name.\n");
SSL_free(ssl);
while (*host++ != '.');
pos += 2;
}
if ( strcmp(host, pos))
{
WRITELOG("SSL_get_peer_certificate() error: Broker %s dosen't match the host name %s\n", peer_CN, host);
SSL_free(_ssl);
_ssl = 0;
return false;
}
if (_session == 0)
{
_session = sess;
_session = SSL_get1_session(_ssl);
}
_ssl = ssl;
_numOfInstance++;
_sslValid = true;
return true;
}
@@ -372,7 +440,11 @@ int Network::send(const uint8_t* buf, uint16_t length)
bool writeBlockedOnRead = false;
int bpos = 0;
if (_secureFlg)
if (!_secureFlg)
{
return TCPStack::send(buf, length);
}
else
{
_mutex.lock();
_busy = true;
@@ -387,7 +459,7 @@ int Network::send(const uint8_t* buf, uint16_t length)
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
if (activity > 0)
{
if (FD_ISSET(getSock(), &wset) || (writeBlockedOnRead && FD_ISSET(getSock(), &rset)))
if (FD_ISSET(getSock(), &wset) || (writeBlockedOnRead && FD_ISSET(getSock(), &rset)))
{
writeBlockedOnRead = false;
@@ -421,10 +493,6 @@ int Network::send(const uint8_t* buf, uint16_t length)
}
}
}
else
{
return TCPStack::send(buf, length);
}
}
int Network::recv(uint8_t* buf, uint16_t len)
@@ -438,92 +506,107 @@ int Network::recv(uint8_t* buf, uint16_t len)
fd_set rset;
fd_set wset;
if (_secureFlg)
if (!_secureFlg)
{
if (_busy)
return TCPStack::recv(buf, len);
}
if (_busy)
{
return 0;
}
_mutex.lock();
_busy = true;
loop: do
{
readBlockedOnWrite = false;
readBlocked = false;
rlen = SSL_read(_ssl, buf + bpos, len - bpos);
switch (SSL_get_error(_ssl, rlen))
{
return 0;
case SSL_ERROR_NONE:
_busy = false;
_mutex.unlock();
return rlen + bpos;
break;
case SSL_ERROR_ZERO_RETURN:
SSL_shutdown(_ssl);
_ssl = 0;
TCPStack::close();
_busy = false;
_mutex.unlock();
return -1;
break;
case SSL_ERROR_WANT_READ:
readBlocked = true;
break;
case SSL_ERROR_WANT_WRITE:
readBlockedOnWrite = true;
break;
default:
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("Network::recv() %s\n", errmsg);
_busy = false;
_mutex.unlock();
return -1;
}
_mutex.lock();
_busy = true;
} while (SSL_pending(_ssl) && !readBlocked);
loop: do
bpos += rlen;
while (true)
{
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(getSock(), &rset);
FD_SET(getSock(), &wset);
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
if (activity > 0)
{
readBlockedOnWrite = false;
readBlocked = false;
rlen = SSL_read(_ssl, buf + bpos, len - bpos);
switch (SSL_get_error(_ssl, rlen))
if ((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead)
|| (readBlockedOnWrite && FD_ISSET(getSock(), &wset)))
{
case SSL_ERROR_NONE:
_busy = false;
_mutex.unlock();
return rlen + bpos;
break;
case SSL_ERROR_ZERO_RETURN:
SSL_shutdown(_ssl);
_ssl = 0;
TCPStack::close();
_busy = false;
_mutex.unlock();
return -1;
break;
case SSL_ERROR_WANT_READ:
readBlocked = true;
break;
case SSL_ERROR_WANT_WRITE:
readBlockedOnWrite = true;
break;
default:
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("TLSStack::recv() default %s\n", errmsg);
_busy = false;
_mutex.unlock();
return -1;
goto loop;
}
} while (SSL_pending(_ssl) && !readBlocked);
bpos += rlen;
while (true)
}
else
{
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(getSock(), &rset);
FD_SET(getSock(), &wset);
int activity = select(getSock() + 1, &rset, &wset, 0, 0);
if (activity > 0)
{
if ((FD_ISSET(getSock(),&rset) && !writeBlockedOnRead)
|| (readBlockedOnWrite && FD_ISSET(getSock(), &wset)))
{
goto loop;
}
}
else
{
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("TLSStack::recv() select %s\n", errmsg);
_busy = false;
_mutex.unlock();
return -1;
}
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
WRITELOG("TLSStack::recv() select %s\n", errmsg);
_busy = false;
_mutex.unlock();
return -1;
}
}
return TCPStack::recv(buf, len);
}
void Network::close(void)
{
if (_secureFlg)
{
_sslValid = false;
SSL_free(_ssl);
_ssl = 0;
}
TCPStack::close();
}
bool Network::isValid()
{
if (!_secureFlg)
if (_secureFlg)
{
if (_sslValid && !_busy)
{
return true;
}
}
else
{
return TCPStack::isValid();
}
if (_ssl)
{
return true;
}
return false;
}
@@ -533,12 +616,11 @@ void Network::disconnect()
{
SSL_shutdown(_ssl);
_ssl = 0;
TCPStack::close();
}
else
{
TCPStack::close();
}
_sslValid = false;
_busy = false;
TCPStack::close();
}
int Network::getSock()
@@ -546,18 +628,6 @@ int Network::getSock()
return TCPStack::getSock();
}
SSL* Network::getSSL()
{
if (_secureFlg)
{
return _ssl;
}
else
{
return 0;
}
}
bool Network::isSecure()
{
return _secureFlg;

View File

@@ -71,26 +71,27 @@ public:
Network(bool secure);
virtual ~Network();
bool connect(const char* host, const char* service);
void disconnect();
int send(const uint8_t* buf, uint16_t length);
int recv(uint8_t* buf, uint16_t len);
bool connect(const char* host, const char* port, const char* caPath, const char* caFile, const char* sert, const char* prvkey);
bool connect(const char* host, const char* port);
void disconnect(void);
void close(void);
int send(const uint8_t* buf, uint16_t length);
int recv(uint8_t* buf, uint16_t len);
bool isValid();
bool isSecure();
int getSock();
SSL* getSSL();
bool isValid(void);
bool isSecure(void);
int getSock(void);
private:
static SSL_CTX* _ctx;
static int _numOfInstance;
static SSL_SESSION* _session;
SSL_SESSION* _session;
SSL* _ssl;
bool _secureFlg;
bool _disconReq;
Mutex _mutex;
bool _busy;
bool _sslValid;
};
#endif /* NETWORK_H_ */