28 #include <QSslConfiguration> 37 #include <openssl/pem.h> 38 #include <openssl/x509.h> 39 #include <openssl/bn.h> 66 m_socketDescriptor(SocketDescriptor),
67 m_address(QHostAddress::Null),
77 m_socketDescriptor(0),
88 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Key generation..."));
92 bool TorcWebSocketThread::CreateCerts(
const QString &CertFile,
const QString &KeyFile)
94 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Generating RSA key"));
98 #if OPENSSL_VERSION_NUMBER < 0x10100000L 102 BN_GENCB *cb = BN_GENCB_new();
107 BN_set_word(e, RSA_F4);
108 #if OPENSSL_VERSION_NUMBER < 0x10100000L 109 RSA_generate_key_ex(rsa, 4096, e, &cb);
111 RSA_generate_key_ex(rsa, 4096, e, cb);
114 #if OPENSSL_VERSION_NUMBER >= 0x10100000L 119 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to generate RSA key"));
123 EVP_PKEY *privatekey = EVP_PKEY_new();
124 if(!EVP_PKEY_assign_RSA(privatekey, rsa))
126 EVP_PKEY_free(privatekey);
127 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to create RSA key"));
131 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Generating X509 certificate"));
132 X509 *x509 = X509_new();
134 QString timenow = QString::number(QDateTime::currentMSecsSinceEpoch());
135 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"New cert serial number: %1").arg(timenow));
136 BIGNUM *bn = BN_new();
137 if (BN_dec2bn(&bn, timenow.toLatin1().constData()) != timenow.size())
138 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Conversion error"));
139 ASN1_INTEGER *sno = ASN1_INTEGER_new();
140 sno = BN_to_ASN1_INTEGER(bn, sno);
141 X509_set_serialNumber(x509, sno);
143 ASN1_INTEGER_free(sno);
144 X509_gmtime_adj(X509_get_notBefore(x509), 0);
145 X509_gmtime_adj(X509_get_notAfter(x509), 315360000L);
146 X509_set_pubkey(x509, privatekey);
147 X509_NAME *name = X509_get_subject_name(x509);
148 X509_NAME_add_entry_by_txt(name,
"C", MBSTRING_ASC, (
unsigned char *)
"GB", -1, -1, 0);
149 X509_NAME_add_entry_by_txt(name,
"O", MBSTRING_ASC, (
unsigned char *)
"SelfSignedCo", -1, -1, 0);
150 X509_NAME_add_entry_by_txt(name,
"OU", MBSTRING_ASC, (
unsigned char *)
"SelfSignedCo", -1, -1, 0);
151 X509_NAME_add_entry_by_txt(name,
"CN", MBSTRING_ASC, (
unsigned char *)
"localhost", -1, -1, 0);
152 X509_set_issuer_name(x509, name);
153 if(!X509_sign(x509, privatekey, EVP_sha256()))
156 EVP_PKEY_free(privatekey);
157 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to sign certificate"));
161 FILE* certfile = fopen(CertFile.toLocal8Bit().constData(),
"wb");
165 EVP_PKEY_free(privatekey);
166 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to open '%1' for writing").arg(CertFile));
169 bool success = PEM_write_X509(certfile, x509);
174 EVP_PKEY_free(privatekey);
175 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to write to '%1'").arg(CertFile));
179 FILE* keyfile = fopen(KeyFile.toLocal8Bit().constData(),
"wb");
183 EVP_PKEY_free(privatekey);
184 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to open '%1' for writing").arg(KeyFile));
188 success = PEM_write_PrivateKey(keyfile, privatekey,
nullptr,
nullptr, 0,
nullptr,
nullptr);
191 EVP_PKEY_free(privatekey);
195 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Failed to write to '%1'").arg(KeyFile));
199 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Cert file saved as '%1'").arg(CertFile));
200 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Key file saved as '%1'").arg(KeyFile));
202 if (chmod(CertFile.toLocal8Bit().constData(), S_IRUSR | S_IWUSR) != 0)
203 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to set permissions for '%1' - this is not fatal but may present a security risk").arg(CertFile));
204 if (chmod(KeyFile.toLocal8Bit().constData(), S_IRUSR | S_IWUSR) != 0)
205 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to set permissions for '%1' - this is not fatal but may present a security risk").arg(KeyFile));
209 void TorcWebSocketThread::SetupSSL(
void)
211 static bool SSLDefaultsSet =
false;
212 static QMutex SSLDefaultsLock(QMutex::Recursive);
215 QMutexLocker locker(&SSLDefaultsLock);
219 SSLDefaultsSet =
true;
220 QSslConfiguration config;
222 #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) 223 config.setProtocol(QSsl::TlsV1_2OrLater);
224 config.setCiphers(QSslConfiguration::supportedCiphers());
226 config.setProtocol(QSsl::TlsV1_2);
227 config.setCiphers(QSslSocket::supportedCiphers());
231 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"SSL: looking for cert in '%1'").arg(certlocation));
233 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"SSL: looking for key in '%1'").arg(keylocation));
236 if (!QFile::exists(certlocation))
239 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to find cert"));
241 if (!QFile::exists(keylocation))
244 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Failed to find key"));
247 if (create && !CreateCerts(certlocation, keylocation))
249 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"SSL key/cert creation failed - server connections will fail"));
253 QFile certFile(certlocation);
254 certFile.open(QIODevice::ReadOnly);
255 if (certFile.isOpen())
257 QSslCertificate certificate(&certFile, QSsl::Pem);
258 if (!certificate.isNull())
260 config.setLocalCertificate(certificate);
261 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"SSL: cert loaded"));
265 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"SSL: error loading/reading cert file"));
271 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"SSL: failed to open cert file for reading"));
274 QFile keyFile(keylocation);
275 keyFile.open(QIODevice::ReadOnly);
276 if (keyFile.isOpen())
278 QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem);
281 config.setPrivateKey(key);
282 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"SSL: key loaded"));
286 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"SSL: error loading/reading key file"));
292 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"SSL: failed to open key file for reading"));
294 QSslConfiguration::setDefaultConfiguration(config);
300 if (m_secure && m_socketDescriptor)
303 if (m_socketDescriptor)
304 m_webSocket =
new TorcWebSocket(
this, m_socketDescriptor, m_secure);
306 m_webSocket =
new TorcWebSocket(
this, m_address, m_port, m_secure, m_protocol);
314 m_webSocket->
Start();
321 m_webSocket =
nullptr;
void Finish(void) override
void ConnectionUpgraded(void)
void ConnectionUpgraded(void)
void Start(void) override
int SSLCallback(int, int, BN_GENCB *)
TorcWebSocketThread(qintptr SocketDescriptor, bool Secure)
void CancelRequest(TorcRPCRequest *Request)
Cancel a Remote Procedure Call.
A class encapsulating a Remote Procedure Call.
TorcWebSocket(TorcWebSocketThread *Parent, qintptr SocketDescriptor, bool Secure)
void ConnectionEstablished(void)
void CancelRequestSignal(TorcRPCRequest *Request)
#define LOG(_MASK_, _LEVEL_, _STRING_)
void CancelRequest(TorcRPCRequest *Request)
A Torc specific wrapper around QThread.
void RemoteRequest(TorcRPCRequest *Request)
Initiate a Remote Procedure Call.
QString GetTorcConfigDir(void)
Return the path to the application configuration directory.
void Start(void)
Initialise the websocket once its parent thread is ready.
void ConnectionEstablished(void)
void RemoteRequest(TorcRPCRequest *Request)
void RemoteRequestSignal(TorcRPCRequest *Request)