mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
add Hue EntertainmentAPI + Forwarder & other Fixes (#592)
* whitespaces + typo fixes * JS / LGTM fixes * SSDP Handler crash fix * MessageForwarder handlePriorityChanges Slave fixes * use aboutToQuit Signal * complete rewriten Hue Entertainment API structure combined Philips Hue and Entertainment API with new MbedTLS based SSL UDP Provider * add required cross-compile submodules * logical rebuild fn: initLeds, setLights + new logs -more detailed checks and error handling inside iniLeds and setLights - logical script procedure before ProviderUdpSSL init - first steps for multiple ProviderUdpSSL usage - better fallback support to old RestAPI, if entertainment api is not supported - just 4 u LordGrey: new log fn for cosmetic config outputs ;) * add OSX CompileHowTo - undo from CrossCompileHowTo * whitespace fixes * lightID toString fix * fix unsigned int E-API + debug output * bugfixes, reworked black signal detection, wizard: - change device config field light-ids from int to string -> real unsigned int fix - add signal detection brightness minimum threshold value 0.0 for 0% brightness - 1.0 for 100% brightness to count for blacklight signal detection reason: input may not 100% black, like mine - i have a deep dark gray input signal -> my threshold value is set to 0.005 for 0.5% minimum brightness = 1 (from max 255) to count as black - wizard optimations, with fallback without entertainment support (beta state) - whitespace fixes * cleanup + minor fixes * change fixed Hue UPD SSL config to _devConfig paras * Hotfix SSL Connection, new light models, wizard: - Fix UPD SSL Connection failed Problems - add new supported gamut C light models: LCG002, LCA001, LCA002, LCA003 - wizard: extend fallback support to classic mode + hints * whitespace, typo fix * uncheck useEntertainmentAPI, if noAPISupport detected + hint * coredump fix -> add _blackLightsTimer nullptr init * code cleanup / remove old debugs + whitespacefixes * add gamut C LCP001, LCP002 * SSL UDP config made more flexible + remove qDebug -> switch to hyerion.ng _log -> replace logCommand with verbose -> code cleanups etc... * extended mbedtls debugging infos * add adjustable ssl timeout settings * error handling * streamdebugger bugfixes * UPDSSL psk / psk_identity bugfixes! + hue wizard fn typo fix + - verbose option available without dependencies - whitespace fixes * Philips Hue Assistant now recognizes non-original bridges better... + Added note if no clientkey is set when using the entertainment API + User creation (+ clientkey) for non-original bridges can now also be used + Minor changes and bug fixes * CMAKE mbedTLS detection * minor bug fixes + code cleanups * FindMbedTLS.cmake remove Path-Hints + wizard.js: ajax timeout handling Test - content_grabber.js: run relevant code only, if V4L2_AVAIL is true: conf_grabber don't displays other devices, if V4L2 is not available * compile mbedtls via cmake as static lib * remove libmbedtls-dev from compileHowto / scripts * Fix Windows build * Fix windows build (part 2) * removed unnecessary osx x11 include directory path * QTimer Shutdown bugfix * cmake win32 fix + minor bugfixes * cmake debug msg used mbedtls libs * Bugfix: noSignalDetection wasn't switchedOn again if no signal was previously detected * Some code fixes based on alerts from lgtm.com Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
This commit is contained in:
@@ -428,8 +428,6 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,16 +2,38 @@
|
||||
|
||||
// STL includes
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QTimer>
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QStringList>
|
||||
|
||||
// Leddevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderUdpSSL.h"
|
||||
|
||||
// Forward declaration
|
||||
struct CiColorTriangle;
|
||||
/**
|
||||
* A XY color point in the color space of the hue system without brightness.
|
||||
*/
|
||||
struct XYColor
|
||||
{
|
||||
/// X component.
|
||||
double x;
|
||||
/// Y component.
|
||||
double y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Color triangle to define an available color space for the hue lamps.
|
||||
*/
|
||||
struct CiColorTriangle
|
||||
{
|
||||
XYColor red, green, blue;
|
||||
};
|
||||
|
||||
/**
|
||||
* A color point in the color space of the hue system.
|
||||
@@ -37,14 +59,14 @@ struct CiColor
|
||||
///
|
||||
/// @return color point
|
||||
///
|
||||
static CiColor rgbToCiColor(double red, double green, double blue, CiColorTriangle colorSpace);
|
||||
static CiColor rgbToCiColor(double red, double green, double blue, const CiColorTriangle &colorSpace);
|
||||
|
||||
///
|
||||
/// @param p the color point to check
|
||||
///
|
||||
/// @return true if the color point is covered by the lamp color space
|
||||
///
|
||||
static bool isPointInLampsReach(CiColor p, CiColorTriangle colorSpace);
|
||||
static bool isPointInLampsReach(CiColor p, const CiColorTriangle &colorSpace);
|
||||
|
||||
///
|
||||
/// @param p1 point one
|
||||
@@ -53,7 +75,7 @@ struct CiColor
|
||||
///
|
||||
/// @return the cross product between p1 and p2
|
||||
///
|
||||
static double crossProduct(CiColor p1, CiColor p2);
|
||||
static double crossProduct(XYColor p1, XYColor p2);
|
||||
|
||||
///
|
||||
/// @param a reference point one
|
||||
@@ -64,7 +86,7 @@ struct CiColor
|
||||
///
|
||||
/// @return the closest color point of p to a and b
|
||||
///
|
||||
static CiColor getClosestPointToPoint(CiColor a, CiColor b, CiColor p);
|
||||
static XYColor getClosestPointToPoint(XYColor a, XYColor b, CiColor p);
|
||||
|
||||
///
|
||||
/// @param p1 point one
|
||||
@@ -73,20 +95,12 @@ struct CiColor
|
||||
///
|
||||
/// @return the distance between the two points
|
||||
///
|
||||
static double getDistanceBetweenTwoPoints(CiColor p1, CiColor p2);
|
||||
static double getDistanceBetweenTwoPoints(CiColor p1, XYColor p2);
|
||||
};
|
||||
|
||||
bool operator==(const CiColor& p1, const CiColor& p2);
|
||||
bool operator!=(const CiColor& p1, const CiColor& p2);
|
||||
|
||||
/**
|
||||
* Color triangle to define an available color space for the hue lamps.
|
||||
*/
|
||||
struct CiColorTriangle
|
||||
{
|
||||
CiColor red, green, blue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple class to hold the id, the latest color, the color space and the original state.
|
||||
*/
|
||||
@@ -120,13 +134,12 @@ public:
|
||||
///
|
||||
/// @param transitionTime the transition time between colors in multiples of 100 ms
|
||||
///
|
||||
void setTransitionTime(unsigned int _transitionTime);
|
||||
void setTransitionTime(unsigned int transitionTime);
|
||||
|
||||
///
|
||||
/// @param color the color to set
|
||||
///
|
||||
void setColor(const CiColor& _color);
|
||||
|
||||
void setColor(const CiColor& color);
|
||||
|
||||
unsigned int getId() const;
|
||||
|
||||
@@ -138,9 +151,7 @@ public:
|
||||
/// @return the color space of the light determined by the model id reported by the bridge.
|
||||
CiColorTriangle getColorSpace() const;
|
||||
|
||||
|
||||
QString getOriginalState();
|
||||
|
||||
QString getOriginalState() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -167,7 +178,7 @@ private:
|
||||
CiColor _originalColor;
|
||||
};
|
||||
|
||||
class LedDevicePhilipsHueBridge : public LedDevice
|
||||
class LedDevicePhilipsHueBridge : public ProviderUdpSSL
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -183,24 +194,22 @@ public:
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// @param route the route of the POST request.
|
||||
///
|
||||
/// @param content the content of the POST request.
|
||||
///
|
||||
void post(const QString& route, const QString& content);
|
||||
QJsonDocument post(const QString& route, const QString& content);
|
||||
|
||||
void setLightState(unsigned int lightId = 0, QString state = "");
|
||||
|
||||
const QMap<quint16,QJsonObject>& getLightMap();
|
||||
|
||||
// /// Set device in error state
|
||||
// ///
|
||||
// /// @param errorMsg The error message to be logged
|
||||
// ///
|
||||
// virtual void setInError( const QString& errorMsg) override;
|
||||
const QMap<quint16,QJsonObject>& getGroupMap();
|
||||
|
||||
QString getGroupName(unsigned int groupId = 0);
|
||||
|
||||
QJsonArray getGroupLights(unsigned int groupId = 0);
|
||||
|
||||
public slots:
|
||||
///
|
||||
@@ -209,11 +218,6 @@ public slots:
|
||||
virtual int open(void) override;
|
||||
virtual int open( const QString& hostname, const QString& port, const QString& username );
|
||||
|
||||
//signals:
|
||||
// ///
|
||||
// /// Emits with a QMap of current bridge light/value pairs
|
||||
// ///
|
||||
// void newLights(QMap<quint16,QJsonObject> map);
|
||||
protected:
|
||||
|
||||
/// Ip address of the bridge
|
||||
@@ -222,6 +226,18 @@ protected:
|
||||
/// User name for the API ("newdeveloper")
|
||||
QString _username;
|
||||
|
||||
bool _useHueEntertainmentAPI;
|
||||
|
||||
QJsonDocument getGroupState( unsigned int groupId );
|
||||
QJsonDocument setGroupState( unsigned int groupId, bool state);
|
||||
|
||||
bool isStreamOwner(const QString streamOwner);
|
||||
bool initMaps();
|
||||
|
||||
void log(const char* msg, const char* type, ...);
|
||||
|
||||
const int * getCiphersuites() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
@@ -267,6 +283,11 @@ private:
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply );
|
||||
|
||||
QJsonDocument getAllBridgeInfos();
|
||||
void setBridgeConfig( QJsonDocument doc );
|
||||
void setLightsMap( QJsonDocument doc );
|
||||
void setGroupMap( QJsonDocument doc );
|
||||
|
||||
/// QNetworkAccessManager for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
|
||||
@@ -282,10 +303,9 @@ private:
|
||||
bool _isHueEntertainmentReady;
|
||||
|
||||
QMap<quint16,QJsonObject> _lightsMap;
|
||||
QMap<quint16,QJsonObject> _groupsMap;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implementation for the Philips Hue system.
|
||||
*
|
||||
@@ -296,7 +316,6 @@ private:
|
||||
*/
|
||||
class LedDevicePhilipsHue: public LedDevicePhilipsHueBridge
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -337,10 +356,16 @@ public:
|
||||
unsigned int getLightsCount() const { return _lightsCount; }
|
||||
void setLightsCount( unsigned int lightsCount);
|
||||
|
||||
bool initStream();
|
||||
bool getStreamGroupState();
|
||||
bool setStreamGroupState(bool state);
|
||||
bool startStream();
|
||||
bool stopStream();
|
||||
|
||||
void setOnOffState(PhilipsHueLight& light, bool on);
|
||||
void setTransitionTime(PhilipsHueLight& light, unsigned int transitionTime);
|
||||
void setColor(PhilipsHueLight& light, const CiColor& color, double brightnessFactor);
|
||||
void setState(PhilipsHueLight& light, bool on, const CiColor& color, double brightnessFactor, unsigned int transitionTime);
|
||||
void setTransitionTime(PhilipsHueLight& light);
|
||||
void setColor(PhilipsHueLight& light, CiColor& color);
|
||||
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
|
||||
|
||||
void restoreOriginalState();
|
||||
|
||||
@@ -357,7 +382,9 @@ private slots:
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
void updateLights(QMap<quint16, QJsonObject> map);
|
||||
bool updateLights(QMap<quint16, QJsonObject> map);
|
||||
|
||||
void noSignalTimeout();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -374,6 +401,7 @@ protected:
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
///
|
||||
bool initLeds();
|
||||
bool reinitLeds();
|
||||
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
@@ -386,8 +414,18 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
bool setLights();
|
||||
|
||||
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
void writeStream();
|
||||
|
||||
bool noSignalDetection();
|
||||
|
||||
void stopBlackTimeoutTimer();
|
||||
|
||||
QByteArray prepareStreamData();
|
||||
|
||||
///
|
||||
bool _switchOffOnBlack;
|
||||
/// The brightness factor to multiply on color change.
|
||||
@@ -397,6 +435,8 @@ private:
|
||||
unsigned int _transitionTime;
|
||||
|
||||
bool _isRestoreOrigState;
|
||||
bool _lightStatesRestored;
|
||||
bool _isInitLeds;
|
||||
|
||||
/// Array of the light ids.
|
||||
std::vector<unsigned int> _lightIds;
|
||||
@@ -404,6 +444,26 @@ private:
|
||||
std::vector<PhilipsHueLight> _lights;
|
||||
|
||||
unsigned int _lightsCount;
|
||||
unsigned int _groupId;
|
||||
|
||||
double _brightnessMin;
|
||||
double _brightnessMax;
|
||||
|
||||
bool _allLightsBlack;
|
||||
|
||||
QTimer* _blackLightsTimer;
|
||||
unsigned int _blackLightsTimeout;
|
||||
double _brightnessThreshold;
|
||||
|
||||
int _handshake_timeout_min;
|
||||
int _handshake_timeout_max;
|
||||
int _ssl_read_timeout;
|
||||
|
||||
bool _stopConnection;
|
||||
|
||||
QString _groupName;
|
||||
QString _streamOwner;
|
||||
|
||||
int start_retry_left;
|
||||
int stop_retry_left;
|
||||
};
|
||||
|
@@ -77,7 +77,7 @@ bool ProviderUdp::initNetwork()
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_udpSocket =new QUdpSocket(this);
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
|
||||
if ( _udpSocket != nullptr)
|
||||
{
|
||||
|
801
libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
Normal file
801
libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
Normal file
@@ -0,0 +1,801 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
|
||||
// Linux includes
|
||||
#include <fcntl.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
// Local Hyperion includes
|
||||
#include "ProviderUdpSSL.h"
|
||||
|
||||
ProviderUdpSSL::ProviderUdpSSL()
|
||||
: LedDevice()
|
||||
, client_fd()
|
||||
, entropy()
|
||||
, ssl()
|
||||
, conf()
|
||||
, ctr_drbg()
|
||||
, timer()
|
||||
, _transport_type("DTLS")
|
||||
, _custom("dtls_client")
|
||||
, _address("127.0.0.1")
|
||||
, _defaultHost("127.0.0.1")
|
||||
, _port(1)
|
||||
, _ssl_port(1)
|
||||
, _server_name()
|
||||
, _psk()
|
||||
, _psk_identity()
|
||||
, _read_timeout(0)
|
||||
, _handshake_timeout_min(400)
|
||||
, _handshake_timeout_max(1000)
|
||||
, _handshake_attempts(5)
|
||||
, _retry_left(MAX_RETRY)
|
||||
, _stopConnection(true)
|
||||
, _debugStreamer(false)
|
||||
, _debugLevel(0)
|
||||
{
|
||||
_deviceReady = false;
|
||||
_latchTime_ms = 1;
|
||||
}
|
||||
|
||||
ProviderUdpSSL::~ProviderUdpSSL()
|
||||
{
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_debugStreamer = deviceConfig["debugStreamer"].toBool(false);
|
||||
_debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
|
||||
|
||||
//PSK Pre Shared Key
|
||||
_psk = deviceConfig["psk"].toString();
|
||||
_psk_identity = deviceConfig["psk_identity"].toString();
|
||||
_port = deviceConfig["sslport"].toInt(2100);
|
||||
_server_name = deviceConfig["servername"].toString();
|
||||
|
||||
if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
|
||||
if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
|
||||
if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
|
||||
if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
|
||||
if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
|
||||
if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
|
||||
if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
|
||||
|
||||
configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
|
||||
configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
|
||||
|
||||
configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
|
||||
configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
|
||||
configLog( "SSL Port", "%d", _port );
|
||||
configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
|
||||
configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
|
||||
configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
|
||||
configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
|
||||
configLog( "SSL Retry Left", "%d", _retry_left );
|
||||
configLog( "SSL Read Timeout", "%d", _read_timeout );
|
||||
configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
|
||||
configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
|
||||
configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
|
||||
|
||||
if ( _address.setAddress(host) )
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if ( info.addresses().isEmpty() )
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
|
||||
QString errortext = QString("Invalid target address [%1]!").arg(host);
|
||||
this->setInError( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
}
|
||||
|
||||
int config_port = deviceConfig["sslport"].toInt(_port);
|
||||
|
||||
if ( config_port <= 0 || config_port > MAX_PORT_SSL )
|
||||
{
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ssl_port = config_port;
|
||||
Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdpSSL::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "UDP SSL Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
closeSSLConnection();
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::closeSSLConnection()
|
||||
{
|
||||
if( _deviceReady && !_stopConnection )
|
||||
{
|
||||
closeSSLNotify();
|
||||
freeSSLConnection();
|
||||
}
|
||||
}
|
||||
|
||||
const int *ProviderUdpSSL::getCiphersuites()
|
||||
{
|
||||
return mbedtls_ssl_list_ciphersuites();
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::configLog(const char* msg, const char* type, ...)
|
||||
{
|
||||
if( _debugStreamer )
|
||||
{
|
||||
const size_t max_val_length = 1024;
|
||||
char val[max_val_length];
|
||||
va_list args;
|
||||
va_start(args, type);
|
||||
vsnprintf(val, max_val_length, type, args);
|
||||
va_end(args);
|
||||
std::string s = msg;
|
||||
int max = 30;
|
||||
s.append(max - s.length(), ' ');
|
||||
Debug( _log, "%s: %s", s.c_str(), val );
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::sslLog(const QString &msg, const char* errorType)
|
||||
{
|
||||
sslLog( QSTRING_CSTR( msg ), errorType );
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::sslLog(const char* msg, const char* errorType)
|
||||
{
|
||||
if( strcmp("fatal", errorType) == 0 ) Error( _log, "%s", msg );
|
||||
|
||||
if( _debugStreamer )
|
||||
{
|
||||
if( strcmp("debug", errorType) == 0 ) Debug( _log, "%s", msg );
|
||||
if( strcmp("warning", errorType) == 0 ) Warning( _log, "%s", msg );
|
||||
if( strcmp("error", errorType) == 0 ) Error( _log, "%s", msg );
|
||||
}
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::initNetwork()
|
||||
{
|
||||
sslLog( "init SSL Network..." );
|
||||
QMutexLocker locker(&_hueMutex);
|
||||
if (!initConnection()) return false;
|
||||
sslLog( "init SSL Network...ok" );
|
||||
_stopConnection = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::initConnection()
|
||||
{
|
||||
sslLog( "init SSL Network -> initConnection" );
|
||||
|
||||
mbedtls_net_init(&client_fd);
|
||||
mbedtls_ssl_init(&ssl);
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
mbedtls_x509_crt_init(&cacert);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
if(!seedingRNG()) return false;
|
||||
return setupStructure();
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::seedingRNG()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sslLog( "Seeding the random number generator..." );
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
|
||||
sslLog( "Set mbedtls_ctr_drbg_seed..." );
|
||||
|
||||
const char* custom = QSTRING_CSTR( _custom );
|
||||
|
||||
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, reinterpret_cast<const unsigned char *>(custom), strlen(custom))) != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_ctr_drbg_seed FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sslLog( "Seeding the random number generator...ok" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::setupStructure()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sslLog( QString( "Setting up the %1 structure").arg( _transport_type ) );
|
||||
|
||||
//TLS MBEDTLS_SSL_TRANSPORT_STREAM
|
||||
//DTLS MBEDTLS_SSL_TRANSPORT_DATAGRAM
|
||||
|
||||
int transport = ( _transport_type == "DTLS" ) ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM;
|
||||
|
||||
if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, transport, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_config_defaults FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
const int * ciphersuites = getCiphersuites();
|
||||
|
||||
if( _debugStreamer )
|
||||
{
|
||||
int s = ( sizeof( ciphersuites ) ) / sizeof( int );
|
||||
|
||||
QString cipher_values;
|
||||
for(int i=0; i<s; i++)
|
||||
{
|
||||
if(i > 0) cipher_values.append(", ");
|
||||
cipher_values.append(QString::number(ciphersuites[i]));
|
||||
}
|
||||
|
||||
sslLog( ( QString("used ciphersuites value: %1").arg( cipher_values ) ) );
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
//mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
//mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
||||
|
||||
mbedtls_ssl_conf_ciphersuites(&conf, ciphersuites);
|
||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
|
||||
if ( _debugLevel > 0)
|
||||
{
|
||||
mbedtls_ssl_conf_verify(&conf, ProviderUdpSSLVerify, NULL);
|
||||
mbedtls_ssl_conf_dbg(&conf, ProviderUdpSSLDebug, NULL);
|
||||
mbedtls_debug_set_threshold( _debugLevel );
|
||||
}
|
||||
|
||||
if( _read_timeout > 0 ) mbedtls_ssl_conf_read_timeout(&conf, _read_timeout);
|
||||
|
||||
mbedtls_ssl_conf_handshake_timeout(&conf, _handshake_timeout_min, _handshake_timeout_max);
|
||||
|
||||
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_setup FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((ret = mbedtls_ssl_set_hostname(&ssl, QSTRING_CSTR( _server_name ))) != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_set_hostname FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sslLog( QString( "Setting up the %1 structure...ok").arg( _transport_type ) );
|
||||
|
||||
return startUPDConnection();
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::startUPDConnection()
|
||||
{
|
||||
sslLog( "init SSL Network -> startUPDConnection" );
|
||||
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_ssl_session_reset(&ssl);
|
||||
|
||||
if(!setupPSK()) return false;
|
||||
|
||||
sslLog( QString("Connecting to udp %1:%2").arg( _address.toString() ).arg( _ssl_port ) );
|
||||
|
||||
if ((ret = mbedtls_net_connect( &client_fd, _address.toString().toUtf8(), std::to_string(_ssl_port).c_str(), MBEDTLS_NET_PROTO_UDP)) != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_net_connect FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout);
|
||||
mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay);
|
||||
|
||||
sslLog( "Connecting...ok" );
|
||||
|
||||
return startSSLHandshake();
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::setupPSK()
|
||||
{
|
||||
int ret;
|
||||
|
||||
QByteArray pskArray = _psk.toUtf8();
|
||||
QByteArray pskRawArray = QByteArray::fromHex(pskArray);
|
||||
|
||||
QByteArray pskIdArray = _psk_identity.toUtf8();
|
||||
QByteArray pskIdRawArray = pskIdArray;
|
||||
|
||||
if (0 != (ret = mbedtls_ssl_conf_psk( &conf, ( const unsigned char* ) pskRawArray.data(), pskRawArray.length() * sizeof(char), reinterpret_cast<const unsigned char *> ( pskIdRawArray.data() ), pskIdRawArray.length() * sizeof(char) ) ) )
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_conf_psk FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProviderUdpSSL::startSSLHandshake()
|
||||
{
|
||||
sslLog( "init SSL Network -> startSSLHandshake" );
|
||||
|
||||
int ret = 0;
|
||||
|
||||
sslLog( QString( "Performing the SSL/%1 handshake...").arg( _transport_type ) );
|
||||
|
||||
for (unsigned int attempt = 1; attempt <= _handshake_attempts; ++attempt)
|
||||
{
|
||||
sslLog( QString("handshake attempt %1/%2").arg( attempt ).arg( _handshake_attempts ) );
|
||||
do
|
||||
{
|
||||
ret = mbedtls_ssl_handshake(&ssl);
|
||||
}
|
||||
while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_handshake attempt %1/%2 FAILED %3").arg( attempt ).arg( _handshake_attempts ).arg( errorMsg( ret ) ) );
|
||||
}
|
||||
|
||||
QThread::msleep(200);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
sslLog( QString("mbedtls_ssl_handshake FAILED %1").arg( errorMsg( ret ) ), "error" );
|
||||
handleReturn(ret);
|
||||
sslLog( "UDP SSL Connection failed!", "fatal" );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ( mbedtls_ssl_get_verify_result( &ssl ) ) != 0 ) {
|
||||
sslLog( "SSL certificate verification failed!", "fatal" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sslLog( QString( "Performing the SSL/%1 handshake...ok").arg( _transport_type ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::freeSSLConnection()
|
||||
{
|
||||
sslLog( "SSL Connection cleanup..." );
|
||||
|
||||
_stopConnection = true;
|
||||
|
||||
try
|
||||
{
|
||||
mbedtls_ssl_session_reset(&ssl);
|
||||
mbedtls_net_free(&client_fd);
|
||||
mbedtls_ssl_free(&ssl);
|
||||
mbedtls_ssl_config_free(&conf);
|
||||
mbedtls_x509_crt_free(&cacert);
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
sslLog( "SSL Connection cleanup...ok" );
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
sslLog( QString("SSL Connection cleanup Error: %s").arg( e.what() ) );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
sslLog( "SSL Connection cleanup Error: <unknown>" );
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::writeBytes(const unsigned size, const unsigned char * data)
|
||||
{
|
||||
if( _stopConnection ) return;
|
||||
|
||||
QMutexLocker locker(&_hueMutex);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
do
|
||||
{
|
||||
ret = mbedtls_ssl_write(&ssl, data, size);
|
||||
}
|
||||
while (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
handleReturn(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::handleReturn(int ret)
|
||||
{
|
||||
bool closeNotify = false;
|
||||
bool gotoExit = false;
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case MBEDTLS_ERR_SSL_TIMEOUT:
|
||||
sslLog( errorMsg( ret ), "warning" );
|
||||
if ( _retry_left-- > 0 ) return;
|
||||
gotoExit = true;
|
||||
break;
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
||||
sslLog( "SSL Connection was closed gracefully", "warning" );
|
||||
ret = 0;
|
||||
closeNotify = true;
|
||||
break;
|
||||
default:
|
||||
sslLog( QString("mbedtls_ssl_read returned %1").arg( errorMsg( ret ) ), "warning" );
|
||||
gotoExit = true;
|
||||
}
|
||||
|
||||
if (closeNotify)
|
||||
{
|
||||
closeSSLNotify();
|
||||
gotoExit = true;
|
||||
}
|
||||
|
||||
if (gotoExit)
|
||||
{
|
||||
sslLog( "Exit SSL connection" );
|
||||
_stopConnection = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString ProviderUdpSSL::errorMsg(int ret) {
|
||||
|
||||
QString msg;
|
||||
|
||||
#ifdef MBEDTLS_ERROR_C
|
||||
char error_buf[1024];
|
||||
mbedtls_strerror(ret, error_buf, 1024);
|
||||
msg = QString("Last error was: %1 - %2").arg( ret ).arg( error_buf );
|
||||
#else
|
||||
switch (ret)
|
||||
{
|
||||
#if defined(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE)
|
||||
case MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE:
|
||||
msg = "The requested feature is not available. - MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE -0x7080";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_INPUT_DATA)
|
||||
case MBEDTLS_ERR_SSL_BAD_INPUT_DATA:
|
||||
msg = "Bad input parameters to function. - MBEDTLS_ERR_SSL_BAD_INPUT_DATA -0x7100";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_INVALID_MAC)
|
||||
case MBEDTLS_ERR_SSL_INVALID_MAC:
|
||||
msg = "Verification of the message MAC failed. - MBEDTLS_ERR_SSL_INVALID_MAC -0x7180";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_INVALID_RECORD)
|
||||
case MBEDTLS_ERR_SSL_INVALID_RECORD:
|
||||
msg = "An invalid SSL record was received. - MBEDTLS_ERR_SSL_INVALID_RECORD -0x7200";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CONN_EOF)
|
||||
case MBEDTLS_ERR_SSL_CONN_EOF:
|
||||
msg = "The connection indicated an EOF. - MBEDTLS_ERR_SSL_CONN_EOF -0x7280";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER)
|
||||
case MBEDTLS_ERR_SSL_UNKNOWN_CIPHER:
|
||||
msg = "An unknown cipher was received. - MBEDTLS_ERR_SSL_UNKNOWN_CIPHER -0x7300";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN)
|
||||
case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN:
|
||||
msg = "The server has no ciphersuites in common with the client. - MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN -0x7380";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_NO_RNG)
|
||||
case MBEDTLS_ERR_SSL_NO_RNG:
|
||||
msg = "No RNG was provided to the SSL module. - MBEDTLS_ERR_SSL_NO_RNG -0x7400";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE)
|
||||
case MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE:
|
||||
msg = "No client certification received from the client, but required by the authentication mode. - MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE)
|
||||
case MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE:
|
||||
msg = "Our own certificate(s) is/are too large to send in an SSL message. - MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED)
|
||||
case MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED:
|
||||
msg = "The own certificate is not set, but needed by the server. - MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED -0x7580";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED)
|
||||
case MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED:
|
||||
msg = "The own private key or pre-shared key is not set, but needed. - MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED)
|
||||
case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED:
|
||||
msg = "No CA Chain is set, but required to operate. - MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED -0x7680";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE)
|
||||
case MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE:
|
||||
msg = "An unexpected message was received from our peer. - MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE -0x7700";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE)
|
||||
case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE:
|
||||
msg = "A fatal alert message was received from our peer. - MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED)
|
||||
case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED:
|
||||
msg = "Verification of our peer failed. - MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED -0x7800";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
|
||||
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
|
||||
msg = "The peer notified us that the connection is going to be closed. - MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO:
|
||||
msg = "Processing of the ClientHello handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO:
|
||||
msg = "Processing of the ServerHello handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE:
|
||||
msg = "Processing of the Certificate handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST:
|
||||
msg = "Processing of the CertificateRequest handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE:
|
||||
msg = "Processing of the ServerKeyExchange handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE:
|
||||
msg = "Processing of the ServerHelloDone handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE:
|
||||
msg = "Processing of the ClientKeyExchange handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP:
|
||||
msg = "Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP -0x7C80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS:
|
||||
msg = "Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret. - MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS -0x7D00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY:
|
||||
msg = "Processing of the CertificateVerify handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC:
|
||||
msg = "Processing of the ChangeCipherSpec handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_FINISHED)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_FINISHED:
|
||||
msg = "Processing of the Finished handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_ALLOC_FAILED)
|
||||
case MBEDTLS_ERR_SSL_ALLOC_FAILED:
|
||||
msg = "Memory allocation failed. - MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED)
|
||||
case MBEDTLS_ERR_SSL_HW_ACCEL_FAILED:
|
||||
msg = "Hardware acceleration function returned with error. - MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -0x7F80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH)
|
||||
case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
|
||||
msg = "Hardware acceleration function skipped / left alone data. - MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_COMPRESSION_FAILED)
|
||||
case MBEDTLS_ERR_SSL_COMPRESSION_FAILED:
|
||||
msg = "Processing of the compression / decompression failed. - MBEDTLS_ERR_SSL_COMPRESSION_FAILED -0x6F00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION:
|
||||
msg = "Handshake protocol not within min/max boundaries. - MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET)
|
||||
case MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET:
|
||||
msg = "Processing of the NewSessionTicket handshake message failed. - MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED)
|
||||
case MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED:
|
||||
msg = "Session ticket has expired. - MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED -0x6D80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH)
|
||||
case MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH:
|
||||
msg = "Public key type mismatch (eg, asked for RSA key exchange and presented EC key) - MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH -0x6D00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY)
|
||||
case MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY:
|
||||
msg = "Unknown identity received (eg, PSK identity) - MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY -0x6C80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_INTERNAL_ERROR)
|
||||
case MBEDTLS_ERR_SSL_INTERNAL_ERROR:
|
||||
msg = "Internal error (eg, unexpected failure in lower-level module) - MBEDTLS_ERR_SSL_INTERNAL_ERROR -0x6C00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_COUNTER_WRAPPING)
|
||||
case MBEDTLS_ERR_SSL_COUNTER_WRAPPING:
|
||||
msg = "A counter would wrap (eg, too many messages exchanged). - MBEDTLS_ERR_SSL_COUNTER_WRAPPING -0x6B80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO)
|
||||
case MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO:
|
||||
msg = "Unexpected message at ServerHello in renegotiation. - MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED)
|
||||
case MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED:
|
||||
msg = "DTLS client must retry for hello verification. - MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL)
|
||||
case MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL:
|
||||
msg = "A buffer is too small to receive or write a message. - MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE)
|
||||
case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE:
|
||||
msg = "None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). - MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_WANT_READ)
|
||||
case MBEDTLS_ERR_SSL_WANT_READ:
|
||||
msg = "No data of requested type currently available on underlying transport. - MBEDTLS_ERR_SSL_WANT_READ -0x6900";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_WANT_WRITE)
|
||||
case MBEDTLS_ERR_SSL_WANT_WRITE:
|
||||
msg = "Connection requires a write call. - MBEDTLS_ERR_SSL_WANT_WRITE -0x6880";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_TIMEOUT)
|
||||
case MBEDTLS_ERR_SSL_TIMEOUT:
|
||||
msg = "The operation timed out. - MBEDTLS_ERR_SSL_TIMEOUT -0x6800";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CLIENT_RECONNECT)
|
||||
case MBEDTLS_ERR_SSL_CLIENT_RECONNECT:
|
||||
msg = "The client initiated a reconnect from the same port. - MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD)
|
||||
case MBEDTLS_ERR_SSL_UNEXPECTED_RECORD:
|
||||
msg = "Record header looks valid but is not expected. - MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_NON_FATAL)
|
||||
case MBEDTLS_ERR_SSL_NON_FATAL:
|
||||
msg = "The alert message received indicates a non-fatal error. - MBEDTLS_ERR_SSL_NON_FATAL -0x6680";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH)
|
||||
case MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH:
|
||||
msg = "Couldn't set the hash for verifying CertificateVerify. - MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING)
|
||||
case MBEDTLS_ERR_SSL_CONTINUE_PROCESSING:
|
||||
msg = "Internal-only message signaling that further message-processing should be done. - MBEDTLS_ERR_SSL_CONTINUE_PROCESSING -0x6580";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||
case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
|
||||
msg = "The asynchronous operation is not completed yet. - MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_EARLY_MESSAGE)
|
||||
case MBEDTLS_ERR_SSL_EARLY_MESSAGE:
|
||||
msg = "Internal-only message signaling that a message arrived early. - MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480";
|
||||
break;
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||
case MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS:
|
||||
msg = "A cryptographic operation is in progress. - MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
msg.append("Last error was: ").append( QString::number(ret) );
|
||||
}
|
||||
#endif
|
||||
return msg;
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::closeSSLNotify()
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sslLog( "Closing SSL connection..." );
|
||||
/* No error checking, the connection might be closed already */
|
||||
do
|
||||
{
|
||||
ret = mbedtls_ssl_close_notify(&ssl);
|
||||
}
|
||||
while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||
|
||||
sslLog( "SSL Connection successful closed" );
|
||||
}
|
210
libsrc/leddevice/dev_net/ProviderUdpSSL.h
Normal file
210
libsrc/leddevice/dev_net/ProviderUdpSSL.h
Normal file
@@ -0,0 +1,210 @@
|
||||
#pragma once
|
||||
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <utils/Logger.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QHostInfo>
|
||||
#include <QThread>
|
||||
|
||||
//----------- mbedtls
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include <mbedtls/config.h>
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_PLATFORM_C)
|
||||
#include <mbedtls/platform.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#define mbedtls_time time
|
||||
#define mbedtls_time_t time_t
|
||||
#define mbedtls_printf printf
|
||||
#define mbedtls_fprintf fprintf
|
||||
#define mbedtls_snprintf snprintf
|
||||
#define mbedtls_calloc calloc
|
||||
#define mbedtls_free free
|
||||
#define mbedtls_exit exit
|
||||
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
|
||||
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/ssl_ciphersuites.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/timing.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/debug.h>
|
||||
|
||||
#define READ_TIMEOUT_MS 1000
|
||||
#define MAX_RETRY 5
|
||||
|
||||
//----------- END mbedtls
|
||||
|
||||
const ushort MAX_PORT_SSL = 65535;
|
||||
|
||||
class ProviderUdpSSL : public LedDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
ProviderUdpSSL();
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~ProviderUdpSSL() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// values are latched.
|
||||
///
|
||||
/// @param[in] size The length of the data
|
||||
/// @param[in] data The data
|
||||
///
|
||||
void writeBytes(const unsigned size, const uint8_t *data);
|
||||
|
||||
///
|
||||
/// get ciphersuites list from mbedtls_ssl_list_ciphersuites
|
||||
///
|
||||
/// @return const int * array
|
||||
///
|
||||
virtual const int * getCiphersuites();
|
||||
|
||||
void sslLog(const QString &msg, const char* errorType = "debug");
|
||||
void sslLog(const char* msg, const char* errorType = "debug");
|
||||
void configLog(const char* msg, const char* type, ...);
|
||||
|
||||
/**
|
||||
* Debug callback for mbed TLS
|
||||
* Just prints on the USB serial port
|
||||
*/
|
||||
static void ProviderUdpSSLDebug(void *ctx, int level, const char *file, int line, const char *str)
|
||||
{
|
||||
const char *p, *basename;
|
||||
(void) ctx;
|
||||
/* Extract basename from file */
|
||||
for(p = basename = file; *p != '\0'; p++)
|
||||
{
|
||||
if(*p == '/' || *p == '\\')
|
||||
{
|
||||
basename = p + 1;
|
||||
}
|
||||
}
|
||||
mbedtls_printf("%s:%04d: |%d| %s", basename, line, level, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Certificate verification callback for mbed TLS
|
||||
* Here we only use it to display information on each cert in the chain
|
||||
*/
|
||||
static int ProviderUdpSSLVerify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||
{
|
||||
const uint32_t buf_size = 1024;
|
||||
char *buf = new char[buf_size];
|
||||
(void) data;
|
||||
|
||||
mbedtls_printf("\nVerifying certificate at depth %d:\n", depth);
|
||||
mbedtls_x509_crt_info(buf, buf_size - 1, " ", crt);
|
||||
mbedtls_printf("%s", buf);
|
||||
|
||||
if (*flags == 0)
|
||||
mbedtls_printf("No verification issue for this certificate\n");
|
||||
else
|
||||
{
|
||||
mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", *flags);
|
||||
mbedtls_printf("%s\n", buf);
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// closeSSLNotify and freeSSLConnection
|
||||
///
|
||||
void closeSSLConnection();
|
||||
|
||||
private:
|
||||
|
||||
bool buildConnection();
|
||||
bool initConnection();
|
||||
bool seedingRNG();
|
||||
bool setupStructure();
|
||||
bool startUPDConnection();
|
||||
bool setupPSK();
|
||||
bool startSSLHandshake();
|
||||
void handleReturn(int ret);
|
||||
QString errorMsg(int ret);
|
||||
void closeSSLNotify();
|
||||
void freeSSLConnection();
|
||||
|
||||
mbedtls_net_context client_fd;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_timing_delay_context timer;
|
||||
|
||||
QMutex _hueMutex;
|
||||
QString _transport_type;
|
||||
QString _custom;
|
||||
QHostAddress _address;
|
||||
QString _defaultHost;
|
||||
int _port;
|
||||
int _ssl_port;
|
||||
QString _server_name;
|
||||
QString _psk;
|
||||
QString _psk_identity;
|
||||
uint32_t _read_timeout;
|
||||
uint32_t _handshake_timeout_min;
|
||||
uint32_t _handshake_timeout_max;
|
||||
unsigned int _handshake_attempts;
|
||||
int _retry_left;
|
||||
bool _stopConnection;
|
||||
bool _debugStreamer;
|
||||
int _debugLevel;
|
||||
};
|
Reference in New Issue
Block a user