mirror of
https://github.com/QuasarApp/qca.git
synced 2025-05-08 16:59:33 +00:00
ssl should work now
svn path=/trunk/kdesupport/qca/; revision=238705
This commit is contained in:
parent
273c717362
commit
2c5ec0260e
9
TODO
9
TODO
@ -1,4 +1,11 @@
|
||||
* ssl/tls (also server support)
|
||||
* ciphertest: segfault??
|
||||
* rsatest: segfault??
|
||||
* ssltest: segfault on exit??
|
||||
|
||||
* cipher: option to specify size for genkey
|
||||
* cert: properly check hostnames with wildcards
|
||||
* ssl: server support
|
||||
|
||||
* sasl (also server support)
|
||||
|
||||
* dsa
|
||||
|
@ -8,6 +8,10 @@ UI_DIR = .ui
|
||||
|
||||
INCLUDEPATH += src
|
||||
INCLUDEPATH += plugins
|
||||
HEADERS += src/qca.h
|
||||
HEADERS += src/qca.h src/qcaprovider.h
|
||||
SOURCES += hashtest.cpp src/qca.cpp
|
||||
|
||||
#DEFINES += USE_OPENSSL
|
||||
#SOURCES += plugins/qcaopenssl.cpp
|
||||
#LIBS += -lcrypto -lssl
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include<openssl/ssl.h>
|
||||
#include<openssl/err.h>
|
||||
|
||||
#define NO_AES
|
||||
|
||||
// FIXME: use openssl for entropy instead of stdlib
|
||||
#include<stdlib.h>
|
||||
static bool seeded = false;
|
||||
@ -316,6 +318,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NO_AES
|
||||
class AES128Context : public EVPCipherContext
|
||||
{
|
||||
public:
|
||||
@ -345,6 +348,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class RSAKeyContext : public QCA_RSAKeyContext
|
||||
{
|
||||
@ -751,7 +755,7 @@ public:
|
||||
reset();
|
||||
}
|
||||
|
||||
QCA_CertContext *clone()
|
||||
QCA_CertContext *clone() const
|
||||
{
|
||||
CertContext *c = new CertContext(*this);
|
||||
if(x) {
|
||||
@ -915,6 +919,7 @@ public:
|
||||
static bool ssl_init = false;
|
||||
class SSLContext : public QCA_SSLContext
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum { Success, TryAgain, Error };
|
||||
enum { Idle, Connect, Handshake, Active };
|
||||
@ -951,6 +956,7 @@ public:
|
||||
recvQueue.resize(0);
|
||||
mode = Idle;
|
||||
cc.reset();
|
||||
vr = QCA::SSL::Unknown;
|
||||
}
|
||||
|
||||
bool begin(const QString &_host, const QPtrList<QCA_CertContext> &list)
|
||||
@ -1045,7 +1051,7 @@ public:
|
||||
}
|
||||
else if(ret == Error) {
|
||||
reset();
|
||||
// FIXME: handshaken(false);
|
||||
handshaken(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1073,27 +1079,28 @@ public:
|
||||
cc.reset();
|
||||
code = QCA::SSL::NoCert;
|
||||
}
|
||||
validityResult = code;
|
||||
vr = code;
|
||||
|
||||
mode = Active;
|
||||
// FIXME: handshaken(true);
|
||||
handshaken(true);
|
||||
}
|
||||
else if(ret == Error) {
|
||||
reset();
|
||||
// FIXME: handshaken(false);
|
||||
handshaken(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//if(isOutgoingSSLData()) {
|
||||
// outgoingSSLDataReady();
|
||||
//}
|
||||
if(outgoingDataReady()) {
|
||||
readyReadOutgoing();
|
||||
}
|
||||
|
||||
// try to read incoming unencrypted data
|
||||
sslReadAll();
|
||||
|
||||
//if(isRecvData())
|
||||
// readyRead();
|
||||
if(dataReady()) {
|
||||
readyRead();
|
||||
}
|
||||
}
|
||||
|
||||
int resultToCV(int ret) const
|
||||
@ -1154,11 +1161,16 @@ public:
|
||||
return rc;
|
||||
}
|
||||
|
||||
QCA_CertContext *peerCertificate()
|
||||
QCA_CertContext *peerCertificate() const
|
||||
{
|
||||
return cc.clone();
|
||||
}
|
||||
|
||||
int validityResult() const
|
||||
{
|
||||
return vr;
|
||||
}
|
||||
|
||||
bool dataReady() const
|
||||
{
|
||||
return (recvQueue.size() > 0) ? true: false;
|
||||
@ -1169,27 +1181,22 @@ public:
|
||||
return (BIO_pending(wbio) > 0) ? true: false;
|
||||
}
|
||||
|
||||
/*void putIncomingSSLData(const QByteArray &a)
|
||||
void writeIncoming(const QByteArray &a)
|
||||
{
|
||||
BIO_write(d->rbio, a.data(), a.size());
|
||||
BIO_write(rbio, a.data(), a.size());
|
||||
sslUpdate();
|
||||
}
|
||||
|
||||
bool isOutgoingSSLData()
|
||||
{
|
||||
return (BIO_pending(d->wbio) > 0) ? true: false;
|
||||
}
|
||||
|
||||
QByteArray getOutgoingSSLData()
|
||||
QByteArray readOutgoing()
|
||||
{
|
||||
QByteArray a;
|
||||
|
||||
int size = BIO_pending(d->wbio);
|
||||
int size = BIO_pending(wbio);
|
||||
if(size <= 0)
|
||||
return a;
|
||||
a.resize(size);
|
||||
|
||||
int r = BIO_read(d->wbio, a.data(), size);
|
||||
int r = BIO_read(wbio, a.data(), size);
|
||||
if(r <= 0) {
|
||||
a.resize(0);
|
||||
return a;
|
||||
@ -1200,30 +1207,20 @@ public:
|
||||
return a;
|
||||
}
|
||||
|
||||
void send(const QByteArray &a)
|
||||
void write(const QByteArray &a)
|
||||
{
|
||||
if(d->mode != Active)
|
||||
if(mode != Active)
|
||||
return;
|
||||
|
||||
int oldsize = d->sendQueue.size();
|
||||
d->sendQueue.resize(oldsize + a.size());
|
||||
memcpy(d->sendQueue.data() + oldsize, a.data(), a.size());
|
||||
|
||||
appendArray(&sendQueue, a);
|
||||
processSendQueue();
|
||||
}
|
||||
|
||||
bool isRecvData()
|
||||
QByteArray read()
|
||||
{
|
||||
return (d->recvQueue.size() > 0) ? true: false;
|
||||
}
|
||||
|
||||
QByteArray recv()
|
||||
{
|
||||
QByteArray a = d->recvQueue;
|
||||
a.detach();
|
||||
d->recvQueue.resize(0);
|
||||
QByteArray a = recvQueue.copy();
|
||||
recvQueue.resize(0);
|
||||
return a;
|
||||
}*/
|
||||
}
|
||||
|
||||
void sslReadAll()
|
||||
{
|
||||
@ -1258,7 +1255,7 @@ public:
|
||||
BIO *rbio, *wbio;
|
||||
QString host;
|
||||
CertContext cc;
|
||||
int validityResult;
|
||||
int vr;
|
||||
};
|
||||
|
||||
class QCAOpenSSL : public QCAProvider
|
||||
@ -1274,8 +1271,10 @@ public:
|
||||
QCA::CAP_MD5 |
|
||||
QCA::CAP_BlowFish |
|
||||
QCA::CAP_TripleDES |
|
||||
#ifndef NO_AES
|
||||
QCA::CAP_AES128 |
|
||||
QCA::CAP_AES256 |
|
||||
#endif
|
||||
QCA::CAP_RSA |
|
||||
QCA::CAP_X509 |
|
||||
QCA::CAP_SSL;
|
||||
@ -1292,10 +1291,12 @@ public:
|
||||
return new BlowFishContext;
|
||||
else if(cap == QCA::CAP_TripleDES)
|
||||
return new TripleDESContext;
|
||||
#ifndef NO_AES
|
||||
else if(cap == QCA::CAP_AES128)
|
||||
return new AES128Context;
|
||||
else if(cap == QCA::CAP_AES256)
|
||||
return new AES256Context;
|
||||
#endif
|
||||
else if(cap == QCA::CAP_RSA)
|
||||
return new RSAKeyContext;
|
||||
else if(cap == QCA::CAP_X509)
|
||||
@ -1314,3 +1315,5 @@ QCAProvider *createProviderOpenSSL()
|
||||
{
|
||||
return (new QCAOpenSSL);
|
||||
}
|
||||
|
||||
#include"qcaopenssl.moc"
|
||||
|
@ -6,16 +6,13 @@ TARGET = qcaopenssl
|
||||
|
||||
INCLUDEPATH += ../src
|
||||
|
||||
# Justin
|
||||
INCLUDEPATH += /usr/local/include
|
||||
|
||||
# RH 9
|
||||
INCLUDEPATH += /usr/kerberos/include
|
||||
|
||||
HEADERS = qcaopenssl.h
|
||||
HEADERS = ../src/qcaprovider.h qcaopenssl.h
|
||||
SOURCES = qcaopenssl.cpp
|
||||
DEFINES += QCA_PLUGIN
|
||||
|
||||
# link with OpenSSL
|
||||
LIBS += -L/usr/local/lib -lcrypto
|
||||
LIBS += -lcrypto -lssl
|
||||
|
||||
|
53
src/qca.cpp
53
src/qca.cpp
@ -599,6 +599,12 @@ Cert::~Cert()
|
||||
delete d;
|
||||
}
|
||||
|
||||
void Cert::fromContext(QCA_CertContext *ctx)
|
||||
{
|
||||
delete d->c;
|
||||
d->c = ctx;
|
||||
}
|
||||
|
||||
bool Cert::isNull() const
|
||||
{
|
||||
return d->c->isNull();
|
||||
@ -715,6 +721,9 @@ public:
|
||||
SSL::SSL()
|
||||
{
|
||||
d = new Private;
|
||||
connect(d->c, SIGNAL(handshaken(bool)), SLOT(ctx_handshaken(bool)));
|
||||
connect(d->c, SIGNAL(readyRead()), SLOT(ctx_readyRead()));
|
||||
connect(d->c, SIGNAL(readyReadOutgoing()), SLOT(ctx_readyReadOutgoing()));
|
||||
}
|
||||
|
||||
SSL::~SSL()
|
||||
@ -724,25 +733,41 @@ SSL::~SSL()
|
||||
|
||||
bool SSL::begin(const QString &host, const QPtrList<Cert> &store)
|
||||
{
|
||||
return false;
|
||||
d->cert = Cert();
|
||||
|
||||
// convert the cert list into a context list
|
||||
QPtrList<QCA_CertContext> list;
|
||||
QPtrListIterator<Cert> it(store);
|
||||
for(Cert *cert; (cert = it.current()); ++it)
|
||||
list.append(cert->d->c);
|
||||
|
||||
// begin!
|
||||
if(!d->c->begin(host, list))
|
||||
return false;
|
||||
|
||||
// we don't need this anymore
|
||||
list.setAutoDelete(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SSL::write(const QByteArray &a)
|
||||
{
|
||||
d->c->write(a);
|
||||
}
|
||||
|
||||
QByteArray SSL::read()
|
||||
{
|
||||
return QByteArray();
|
||||
return d->c->read();
|
||||
}
|
||||
|
||||
void SSL::writeIncoming(const QByteArray &a)
|
||||
{
|
||||
d->c->writeIncoming(a);
|
||||
}
|
||||
|
||||
QByteArray SSL::readOutgoing()
|
||||
{
|
||||
return QByteArray();
|
||||
return d->c->readOutgoing();
|
||||
}
|
||||
|
||||
const Cert & SSL::peerCertificate() const
|
||||
@ -752,5 +777,25 @@ const Cert & SSL::peerCertificate() const
|
||||
|
||||
int SSL::certificateValidityResult() const
|
||||
{
|
||||
return NoCert;
|
||||
return d->c->validityResult();
|
||||
}
|
||||
|
||||
void SSL::ctx_handshaken(bool b)
|
||||
{
|
||||
if(b) {
|
||||
// read the cert
|
||||
QCA_CertContext *cc = d->c->peerCertificate();
|
||||
d->cert.fromContext(cc);
|
||||
}
|
||||
handshaken(b);
|
||||
}
|
||||
|
||||
void SSL::ctx_readyRead()
|
||||
{
|
||||
readyRead();
|
||||
}
|
||||
|
||||
void SSL::ctx_readyReadOutgoing()
|
||||
{
|
||||
readyReadOutgoing();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
class QCA_HashContext;
|
||||
class QCA_CipherContext;
|
||||
class QCA_CertContext;
|
||||
|
||||
namespace QCA
|
||||
{
|
||||
@ -254,6 +255,9 @@ namespace QCA
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
friend class SSL;
|
||||
void fromContext(QCA_CertContext *);
|
||||
};
|
||||
|
||||
class SSL : public QObject
|
||||
@ -298,6 +302,11 @@ namespace QCA
|
||||
void readyRead();
|
||||
void readyReadOutgoing();
|
||||
|
||||
private slots:
|
||||
void ctx_handshaken(bool);
|
||||
void ctx_readyRead();
|
||||
void ctx_readyReadOutgoing();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include<qglobal.h>
|
||||
#include<qstring.h>
|
||||
#include<qdatetime.h>
|
||||
#include<qobject.h>
|
||||
#include"qca.h"
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
@ -80,7 +81,7 @@ class QCA_CertContext
|
||||
public:
|
||||
virtual ~QCA_CertContext() {}
|
||||
|
||||
virtual QCA_CertContext *clone()=0;
|
||||
virtual QCA_CertContext *clone() const=0;
|
||||
virtual bool isNull() const=0;
|
||||
virtual bool createFromDER(const char *in, unsigned int len)=0;
|
||||
virtual bool createFromPEM(const char *in, unsigned int len)=0;
|
||||
@ -96,12 +97,25 @@ public:
|
||||
virtual QDateTime notAfter() const=0;
|
||||
};
|
||||
|
||||
class QCA_SSLContext
|
||||
class QCA_SSLContext : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~QCA_SSLContext() {}
|
||||
|
||||
virtual bool begin(const QString &host, const QPtrList<QCA_CertContext> &store)=0;
|
||||
|
||||
virtual void writeIncoming(const QByteArray &a)=0;
|
||||
virtual QByteArray readOutgoing()=0;
|
||||
virtual void write(const QByteArray &a)=0;
|
||||
virtual QByteArray read()=0;
|
||||
virtual QCA_CertContext *peerCertificate() const=0;
|
||||
virtual int validityResult() const=0;
|
||||
|
||||
signals:
|
||||
void handshaken(bool);
|
||||
void readyRead();
|
||||
void readyReadOutgoing();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
246
ssltest.cpp
Normal file
246
ssltest.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
#include<qapplication.h>
|
||||
#include<qdom.h>
|
||||
#include<qfile.h>
|
||||
#include<qsocket.h>
|
||||
#include<qptrlist.h>
|
||||
#include"base64.h"
|
||||
#include"qca.h"
|
||||
|
||||
QCA::Cert readCertXml(const QDomElement &e)
|
||||
{
|
||||
QCA::Cert cert;
|
||||
// there should be one child data tag
|
||||
QDomElement data = e.elementsByTagName("data").item(0).toElement();
|
||||
if(!data.isNull())
|
||||
cert.fromDER(Base64::stringToArray(data.text()));
|
||||
return cert;
|
||||
}
|
||||
|
||||
void showCertInfo(const QCA::Cert &cert)
|
||||
{
|
||||
printf("-- Cert --\n");
|
||||
printf(" CN: %s\n", cert.subject()["CN"].latin1());
|
||||
printf(" Valid from: %s, until %s\n",
|
||||
cert.notBefore().toString().latin1(),
|
||||
cert.notAfter().toString().latin1());
|
||||
printf(" PEM:\n%s\n", cert.toPEM().latin1());
|
||||
}
|
||||
|
||||
QPtrList<QCA::Cert> getRootCerts()
|
||||
{
|
||||
QPtrList<QCA::Cert> list;
|
||||
|
||||
// open the Psi rootcerts file
|
||||
QFile f("/usr/local/share/psi/certs/rootcert.xml");
|
||||
if(!f.open(IO_ReadOnly)) {
|
||||
printf("unable to open %s\n", f.name().latin1());
|
||||
return list;
|
||||
}
|
||||
QDomDocument doc;
|
||||
doc.setContent(&f);
|
||||
f.close();
|
||||
|
||||
QDomElement base = doc.documentElement();
|
||||
if(base.tagName() != "store") {
|
||||
printf("wrong format of %s\n", f.name().latin1());
|
||||
return list;
|
||||
}
|
||||
QDomNodeList cl = base.elementsByTagName("certificate");
|
||||
if(cl.count() == 0) {
|
||||
printf("no certs found in %s\n", f.name().latin1());
|
||||
return list;
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
for(int n = 0; n < (int)cl.count(); ++n) {
|
||||
QCA::Cert *cert = new QCA::Cert(readCertXml(cl.item(n).toElement()));
|
||||
if(cert->isNull()) {
|
||||
printf("error reading cert\n");
|
||||
delete cert;
|
||||
continue;
|
||||
}
|
||||
|
||||
++num;
|
||||
list.append(cert);
|
||||
}
|
||||
printf("imported %d root certs\n", num);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QString resultToString(int result)
|
||||
{
|
||||
QString s;
|
||||
switch(result) {
|
||||
case QCA::SSL::NoCert:
|
||||
s = QObject::tr("The server did not present a certificate.");
|
||||
break;
|
||||
case QCA::SSL::Valid:
|
||||
break;
|
||||
case QCA::SSL::HostMismatch:
|
||||
s = QObject::tr("The hostname does not match the one the certificate was issued to.");
|
||||
break;
|
||||
case QCA::SSL::Rejected:
|
||||
s = QObject::tr("Root CA is marked to reject the specified purpose.");
|
||||
break;
|
||||
case QCA::SSL::Untrusted:
|
||||
s = QObject::tr("Certificate not trusted for the required purpose.");
|
||||
break;
|
||||
case QCA::SSL::SignatureFailed:
|
||||
s = QObject::tr("Invalid signature.");
|
||||
break;
|
||||
case QCA::SSL::InvalidCA:
|
||||
s = QObject::tr("Invalid CA certificate.");
|
||||
break;
|
||||
case QCA::SSL::InvalidPurpose:
|
||||
s = QObject::tr("Invalid certificate purpose.");
|
||||
break;
|
||||
case QCA::SSL::SelfSigned:
|
||||
s = QObject::tr("Certificate is self-signed.");
|
||||
break;
|
||||
case QCA::SSL::Revoked:
|
||||
s = QObject::tr("Certificate has been revoked.");
|
||||
break;
|
||||
case QCA::SSL::PathLengthExceeded:
|
||||
s = QObject::tr("Maximum certificate chain length exceeded.");
|
||||
break;
|
||||
case QCA::SSL::Expired:
|
||||
s = QObject::tr("Certificate has expired.");
|
||||
break;
|
||||
case QCA::SSL::Unknown:
|
||||
default:
|
||||
s = QObject::tr("General certificate validation error.");
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
class SecureTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SecureTest()
|
||||
{
|
||||
sock = new QSocket;
|
||||
connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
|
||||
connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
|
||||
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
|
||||
|
||||
ssl = new QCA::SSL;
|
||||
connect(ssl, SIGNAL(handshaken(bool)), SLOT(ssl_handshaken(bool)));
|
||||
connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
|
||||
connect(ssl, SIGNAL(readyReadOutgoing()), SLOT(ssl_readyReadOutgoing()));
|
||||
|
||||
rootCerts = getRootCerts();
|
||||
}
|
||||
|
||||
~SecureTest()
|
||||
{
|
||||
delete ssl;
|
||||
rootCerts.setAutoDelete(true);
|
||||
rootCerts.clear();
|
||||
delete sock;
|
||||
}
|
||||
|
||||
void start(const QString &_host)
|
||||
{
|
||||
host = _host;
|
||||
printf("Trying %s:443...\n", host.latin1());
|
||||
sock->connectToHost(host, 443);
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void sock_connected()
|
||||
{
|
||||
printf("Connected, starting TLS handshake...\n");
|
||||
ssl->begin(host, rootCerts);
|
||||
}
|
||||
|
||||
void sock_readyRead()
|
||||
{
|
||||
QByteArray buf(sock->bytesAvailable());
|
||||
int num = sock->readBlock(buf.data(), buf.size());
|
||||
if(num < (int)buf.size())
|
||||
buf.resize(num);
|
||||
ssl->writeIncoming(buf);
|
||||
}
|
||||
|
||||
void sock_connectionClosed()
|
||||
{
|
||||
printf("\nConnection closed.\n");
|
||||
quit();
|
||||
}
|
||||
|
||||
void ssl_handshaken(bool b)
|
||||
{
|
||||
if(b) {
|
||||
cert = ssl->peerCertificate();
|
||||
int vr = ssl->certificateValidityResult();
|
||||
|
||||
printf("Successful SSL handshake.\n");
|
||||
if(!cert.isNull())
|
||||
showCertInfo(cert);
|
||||
if(vr == QCA::SSL::Valid)
|
||||
printf("Valid certificate.\n");
|
||||
else
|
||||
printf("Invalid certificate: %s\n", resultToString(vr).latin1());
|
||||
|
||||
printf("Let's try a GET request now.\n");
|
||||
QString req = "GET / HTTP/1.0\nHost: " + host + "\n\n";
|
||||
QCString cs = req.latin1();
|
||||
QByteArray buf(cs.length());
|
||||
memcpy(buf.data(), cs.data(), buf.size());
|
||||
ssl->write(buf);
|
||||
}
|
||||
else {
|
||||
printf("SSL Handshake Error!\n");
|
||||
quit();
|
||||
}
|
||||
}
|
||||
|
||||
void ssl_readyRead()
|
||||
{
|
||||
QByteArray a = ssl->read();
|
||||
QCString cs;
|
||||
cs.resize(a.size()+1);
|
||||
memcpy(cs.data(), a.data(), a.size());
|
||||
printf("%s", cs.data());
|
||||
}
|
||||
|
||||
void ssl_readyReadOutgoing()
|
||||
{
|
||||
QByteArray a = ssl->readOutgoing();
|
||||
sock->writeBlock(a.data(), a.size());
|
||||
}
|
||||
|
||||
private:
|
||||
QString host;
|
||||
QSocket *sock;
|
||||
QCA::SSL *ssl;
|
||||
QCA::Cert cert;
|
||||
QPtrList<QCA::Cert> rootCerts;
|
||||
};
|
||||
|
||||
#include"ssltest.moc"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
QString host = argc > 1 ? argv[1] : "andbit.net";
|
||||
|
||||
if(!QCA::isSupported(QCA::CAP_SSL)) {
|
||||
printf("SSL not supported!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
SecureTest *s = new SecureTest;
|
||||
QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
s->start(host);
|
||||
app.exec();
|
||||
delete s;
|
||||
|
||||
return 0;
|
||||
}
|
13
ssltest.pro
Normal file
13
ssltest.pro
Normal file
@ -0,0 +1,13 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += thread
|
||||
TARGET = ssltest
|
||||
|
||||
MOC_DIR = .moc
|
||||
OBJECTS_DIR = .obj
|
||||
UI_DIR = .ui
|
||||
|
||||
INCLUDEPATH += src
|
||||
INCLUDEPATH += plugins
|
||||
HEADERS += base64.h src/qca.h
|
||||
SOURCES += base64.cpp ssltest.cpp src/qca.cpp
|
||||
|
Loading…
x
Reference in New Issue
Block a user