4
0
mirror of https://github.com/QuasarApp/qca.git synced 2025-05-14 03:29:32 +00:00

a TON of changes

svn path=/trunk/kdesupport/qca/; revision=250071
This commit is contained in:
Justin Karneges 2003-09-10 19:05:37 +00:00
parent d13a80de4e
commit 6c723d8ee5
10 changed files with 623 additions and 528 deletions

34
README

@ -1,33 +1,23 @@
Qt Cryptographic Architecture
-----------------------------
Author: Justin Karneges <justin@affinix.com>
Date: July 10th 2003
Date: September 10th 2003
This library provides a skeleton API for the following features:
This library provides an easy API for the following features:
SSL/TLS
X509
SASL
RSA
Hashing (SHA1, MD5)
Ciphers (BlowFish, 3DES, AES)
RSA
X509
SSL/TLS
SASL
Your application will compile and link in all cases, regardless of
whether or not the installed QCA actually supports the features you
need. Functionality is provided via plugins, which are loaded
automatically.
This solves several issues surrounding security:
1) Compilation. No more "./configure --with-ssl" stupidity. Your
program can always support SSL, changable at runtime.
2) Crypto export. As neither QCA nor your application contain any
actual crypto routines, export hassles are safely dodged.
3) Licenses. As OpenSSL is not GPL-compatible, many secure GPL
programs are violating their own license (and possibly the libraries
they link to). While QCA does not remove this incompatibility, it
does defer it to the plugin space, making your application "clean."
4) No need to roll your own plugins to achieve these things. QCA
does it all for you.
Functionality is supplied via plugins. This is useful for avoiding
dependence on a particular crypto library and makes upgrading easier,
as there is no need to recompile your application when adding or
upgrading a crypto plugin. Also, by pushing crypto functionality into
plugins, your application is free of legal issues, such as export
regulation.
And of course, you get a very simple crypto API for Qt, where you can
do things like:

17
TODO

@ -1,19 +1,20 @@
* rename qcaopenssl to qca-ssl and qcacyrussasl to qca-sasl and move them.
* cipher: option to specify size for genkey
* cert: properly check hostnames with wildcards
* ssl: rename to tls
* ssl: change plugin API to not need Q_OBJECT
* ssl: error signal
* openssl plugin: fixmes and todos
* more optimal plugin loading:
plugins should have versions and names
load on demand
ability to add classes as plugins
ability to set priorities to plugins by name and feature
read plugins from QApplication::libraryPaths() - $DIR/crypto
* openssl plugin:
fixmes and todos
rename SSL to TLS
clean TLSContext, and make sure it reports crypt errors
fix CertContext to properly check hostnames with wildcards
* ssl: client-specified cert
* dsa
* diffie-hellman
* figure out where to install the lib and plugins. maybe Qt plugin path?
* entropy

@ -64,32 +64,32 @@ public:
void resetNeed()
{
need.auth = false;
need.user = false;
need.authzid = false;
need.pass = false;
need.realm = false;
}
void resetHave()
{
have.auth = false;
have.user = false;
have.authzid = false;
have.pass = false;
have.realm = false;
}
void setAuthname(const QString &s)
{
have.auth = true;
auth = s;
}
void setUsername(const QString &s)
{
have.user = true;
user = s;
}
void setAuthzid(const QString &s)
{
have.authzid = true;
authzid = s;
}
void setPassword(const QString &s)
{
have.pass = true;
@ -106,9 +106,9 @@ public:
{
for(int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
if(needp[n].id == SASL_CB_AUTHNAME)
need.auth = true;
need.user = true; // yes, I know these
if(needp[n].id == SASL_CB_USER)
need.user = true;
need.authzid = true; // look backwards
if(needp[n].id == SASL_CB_PASS)
need.pass = true;
if(needp[n].id == SASL_CB_GETREALM)
@ -116,23 +116,23 @@ public:
}
}
void extractHave(sasl_interact_t *need)
void extractHave(sasl_interact_t *needp)
{
for(int n = 0; need[n].id != SASL_CB_LIST_END; ++n) {
if(need[n].id == SASL_CB_AUTHNAME && have.auth)
setValue(&need[n], auth);
if(need[n].id == SASL_CB_USER && have.user)
setValue(&need[n], user);
if(need[n].id == SASL_CB_PASS && have.pass)
setValue(&need[n], pass);
if(need[n].id == SASL_CB_GETREALM && have.realm)
setValue(&need[n], realm);
for(int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) {
if(needp[n].id == SASL_CB_AUTHNAME && have.user)
setValue(&needp[n], user);
if(needp[n].id == SASL_CB_USER && have.authzid)
setValue(&needp[n], authzid);
if(needp[n].id == SASL_CB_PASS && have.pass)
setValue(&needp[n], pass);
if(needp[n].id == SASL_CB_GETREALM && have.realm)
setValue(&needp[n], realm);
}
}
bool missingAny() const
{
if((need.auth && !have.auth) || (need.user && !have.user) || (need.pass && !have.pass) || (need.realm && !have.realm))
if((need.user && !have.user) || (need.authzid && !have.authzid) || (need.pass && !have.pass) || (need.realm && !have.realm))
return true;
return false;
}
@ -140,10 +140,10 @@ public:
QCA_SASLNeedParams missing() const
{
QCA_SASLNeedParams np = need;
if(have.auth)
np.auth = false;
if(have.user)
np.user = false;
if(have.authzid)
np.authzid = false;
if(have.pass)
np.pass = false;
if(have.realm)
@ -170,7 +170,7 @@ public:
QPtrList<void> results;
QCA_SASLNeedParams need;
QCA_SASLNeedParams have;
QString auth, user, pass, realm;
QString user, authzid, pass, realm;
};
static QByteArray makeByteArray(const void *in, unsigned int len)
@ -234,7 +234,7 @@ public:
QByteArray out_buf;
SASLParams params;
QString sc_authname, sc_username;
QString sc_username, sc_authzid;
bool ca_flag, ca_done, ca_skip;
int last_r;
@ -275,8 +275,8 @@ public:
mechlist.clear();
ssf = 0;
maxoutbuf = 0;
sc_authname = "";
sc_username = "";
sc_authzid = "";
}
void resetParams()
@ -324,8 +324,8 @@ public:
static int scb_checkauth(sasl_conn_t *, void *context, const char *requested_user, unsigned, const char *auth_identity, unsigned, const char *, unsigned, struct propctx *)
{
SASLContext *that = (SASLContext *)context;
that->sc_authname = auth_identity;
that->sc_username = requested_user;
that->sc_username = auth_identity; // yeah yeah, it looks
that->sc_authzid = requested_user; // backwards, but it is right
that->ca_flag = true;
return SASL_OK;
}
@ -477,28 +477,28 @@ public:
return params.missing();
}
void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm)
void setClientParams(const QString *user, const QString *authzid, const QString *pass, const QString *realm)
{
if(auth)
params.setAuthname(*auth);
if(user)
params.setUsername(*user);
if(authzid)
params.setAuthzid(*authzid);
if(pass)
params.setPassword(*pass);
if(realm)
params.setRealm(*realm);
}
QString authname() const
{
return sc_authname;
}
QString username() const
{
return sc_username;
}
QString authzid() const
{
return sc_authzid;
}
int nextStep(const QByteArray &in)
{
in_buf = in.copy();
@ -580,7 +580,10 @@ public:
while(1) {
if(need)
params.extractHave(need);
QCString cs(in_buf.data(), in_buf.size()+1);
//printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", cs.data(), in_buf.size());
r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen);
//printf("returned: %d\n", r);
if(r != SASL_INTERACT)
break;

@ -13,8 +13,6 @@
#include<openssl/ssl.h>
#include<openssl/err.h>
#define OSSL_097
#ifndef OSSL_097
#define NO_AES
#endif
@ -944,14 +942,27 @@ public:
};
static bool ssl_init = false;
class SSLContext : public QCA_SSLContext
class TLSContext : public QCA_TLSContext
{
Q_OBJECT
public:
enum { Success, TryAgain, Error };
enum { Good, TryAgain, Bad };
enum { Idle, Connect, Accept, Handshake, Active };
SSLContext()
bool serv;
int mode;
QByteArray sendQueue, recvQueue;
CertContext *cert;
RSAKeyContext *key;
SSL *ssl;
SSL_METHOD *method;
SSL_CTX *context;
BIO *rbio, *wbio;
CertContext cc;
int vr;
TLSContext()
{
if(!ssl_init) {
SSL_library_init();
@ -965,7 +976,7 @@ public:
key = 0;
}
~SSLContext()
~TLSContext()
{
reset();
}
@ -994,22 +1005,44 @@ public:
recvQueue.resize(0);
mode = Idle;
cc.reset();
vr = QCA::SSL::Unknown;
vr = QCA::TLS::Unknown;
}
bool startClient(const QString &_host, const QPtrList<QCA_CertContext> &list)
bool startClient(const QPtrList<QCA_CertContext> &store, const QCA_CertContext &cert, const QCA_RSAKeyContext &key)
{
reset();
serv = false;
method = SSLv23_client_method();
if(!setup(store, cert, key))
return false;
mode = Connect;
return true;
}
bool startServer(const QPtrList<QCA_CertContext> &store, const QCA_CertContext &cert, const QCA_RSAKeyContext &key)
{
reset();
serv = true;
method = SSLv23_server_method();
if(!setup(store, cert, key))
return false;
mode = Accept;
return true;
}
bool setup(const QPtrList<QCA_CertContext> &list, const QCA_CertContext &cc, const QCA_RSAKeyContext &kc)
{
context = SSL_CTX_new(method);
if(!context) {
reset();
return false;
}
// load the certs
// load the cert store
if(!list.isEmpty()) {
X509_STORE *store = SSL_CTX_get_cert_store(context);
QPtrListIterator<QCA_CertContext> it(list);
@ -1017,48 +1050,6 @@ public:
X509_STORE_add_cert(store, cc->x);
}
if(!setup())
return false;
host = _host;
mode = Connect;
sslUpdate();
return true;
}
bool startServer(const QCA_CertContext &cc, const QCA_RSAKeyContext &kc)
{
reset();
serv = true;
method = SSLv23_server_method();
context = SSL_CTX_new(method);
if(!context) {
reset();
return false;
}
if(!setup())
return false;
cert = (CertContext *)cc.clone();
key = (RSAKeyContext *)kc.clone();
if(SSL_use_certificate(ssl, cert->x) != 1) {
reset();
return false;
}
if(SSL_use_RSAPrivateKey(ssl, key->sec) != 1) {
reset();
return false;
}
mode = Accept;
sslUpdate();
return true;
}
bool setup()
{
ssl = SSL_new(context);
if(!ssl) {
reset();
@ -1073,221 +1064,139 @@ public:
// this passes control of the bios to ssl. we don't need to free them.
SSL_set_bio(ssl, rbio, wbio);
// setup the cert to send
if(!cc.isNull() && !kc.isNull()) {
cert = static_cast<CertContext*>(cc.clone());
key = static_cast<RSAKeyContext*>(kc.clone());
if(SSL_use_certificate(ssl, cert->x) != 1) {
reset();
return false;
}
if(SSL_use_RSAPrivateKey(ssl, key->sec) != 1) {
reset();
return false;
}
}
return true;
}
int doConnect()
int handshake(const QByteArray &in, QByteArray *out)
{
int ret = SSL_connect(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else
return Error;
}
else if(ret == 0)
return Error;
return Success;
}
int doAccept()
{
int ret = SSL_accept(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else {
printf("ERR=%s\n", ERR_error_string(ERR_get_error(), NULL));
return Error;
}
}
else if(ret == 0)
return Error;
return Success;
}
int doHandshake()
{
int ret = SSL_do_handshake(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else
return Error;
}
else if(ret == 0)
return Error;
return Success;
}
void sslUpdate()
{
if(mode == Idle)
return;
if(!in.isEmpty())
BIO_write(rbio, in.data(), in.size());
if(mode == Connect) {
int ret = doConnect();
if(ret == Success) {
if(ret == Good) {
mode = Handshake;
}
else if(ret == Error) {
else if(ret == Bad) {
reset();
handshaken(false);
return;
return Error;
}
}
if(mode == Accept) {
int ret = doAccept();
if(ret == Success) {
if(ret == Good) {
getCert();
mode = Active;
handshaken(true);
}
else if(ret == Error) {
else if(ret == Bad) {
reset();
handshaken(false);
return;
return Error;
}
}
if(mode == Handshake) {
int ret = doHandshake();
if(ret == Success) {
// verify the certificate
int code = QCA::SSL::Unknown;
X509 *x = SSL_get_peer_certificate(ssl);
if(x) {
cc.fromX509(x);
X509_free(x);
int ret = SSL_get_verify_result(ssl);
if(ret == X509_V_OK) {
if(cc.matchesAddress(host))
code = QCA::SSL::Valid;
else
code = QCA::SSL::HostMismatch;
}
else
code = resultToCV(ret);
}
else {
cc.reset();
code = QCA::SSL::NoCert;
}
vr = code;
if(ret == Good) {
getCert();
mode = Active;
handshaken(true);
}
else if(ret == Error) {
else if(ret == Bad) {
reset();
handshaken(false);
return;
return Error;
}
}
if(outgoingDataReady()) {
readyReadOutgoing();
// process outgoing
*out = readOutgoing();
if(mode == Active)
return Success;
else
return Continue;
}
void getCert()
{
// verify the certificate
int code = QCA::TLS::Unknown;
X509 *x = SSL_get_peer_certificate(ssl);
if(x) {
cc.fromX509(x);
X509_free(x);
int ret = SSL_get_verify_result(ssl);
if(ret == X509_V_OK)
code = QCA::TLS::Valid;
else
code = resultToCV(ret);
}
else {
cc.reset();
code = QCA::TLS::NoCert;
}
vr = code;
}
bool encode(const QByteArray &plain, QByteArray *to_net)
{
if(mode != Active)
return false;
appendArray(&sendQueue, plain);
if(sendQueue.size() > 0) {
// since we are using memory BIOs, the whole thing can be written successfully
SSL_write(ssl, sendQueue.data(), sendQueue.size());
// TODO: error?
sendQueue.resize(0);
}
// try to read incoming unencrypted data
sslReadAll();
*to_net = readOutgoing();
return true;
}
if(dataReady()) {
readyRead();
bool decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net)
{
if(mode != Active)
return false;
if(!from_net.isEmpty())
BIO_write(rbio, from_net.data(), from_net.size());
QByteArray a;
while(1) {
a.resize(4096);
int x = SSL_read(ssl, a.data(), a.size());
if(x <= 0)
break;
if(x != (int)a.size())
a.resize(x);
appendArray(&recvQueue, a);
}
}
int resultToCV(int ret) const
{
int rc;
*plain = recvQueue.copy();
recvQueue.resize(0);
switch(ret) {
case X509_V_ERR_CERT_REJECTED:
rc = QCA::SSL::Rejected;
break;
case X509_V_ERR_CERT_UNTRUSTED:
rc = QCA::SSL::Untrusted;
break;
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
rc = QCA::SSL::SignatureFailed;
break;
case X509_V_ERR_INVALID_CA:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
rc = QCA::SSL::InvalidCA;
break;
case X509_V_ERR_INVALID_PURPOSE:
rc = QCA::SSL::InvalidPurpose;
break;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
rc = QCA::SSL::SelfSigned;
break;
case X509_V_ERR_CERT_REVOKED:
rc = QCA::SSL::Revoked;
break;
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
rc = QCA::SSL::PathLengthExceeded;
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CRL_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
rc = QCA::SSL::Expired;
break;
case X509_V_ERR_APPLICATION_VERIFICATION:
case X509_V_ERR_OUT_OF_MEM:
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
default:
rc = QCA::SSL::Unknown;
break;
}
return rc;
}
QCA_CertContext *peerCertificate() const
{
return cc.clone();
}
int validityResult() const
{
return vr;
}
bool dataReady() const
{
return (recvQueue.size() > 0) ? true: false;
}
bool outgoingDataReady() const
{
return (BIO_pending(wbio) > 0) ? true: false;
}
void writeIncoming(const QByteArray &a)
{
BIO_write(rbio, a.data(), a.size());
sslUpdate();
// could be outgoing data also
*to_net = readOutgoing();
return true;
}
QByteArray readOutgoing()
{
QByteArray a;
int size = BIO_pending(wbio);
if(size <= 0)
return a;
@ -1300,63 +1209,121 @@ public:
}
if(r != size)
a.resize(r);
return a;
}
void write(const QByteArray &a)
int doConnect()
{
if(mode != Active)
return;
appendArray(&sendQueue, a);
processSendQueue();
int ret = SSL_connect(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else
return Bad;
}
else if(ret == 0)
return Bad;
return Good;
}
QByteArray read()
int doAccept()
{
QByteArray a = recvQueue.copy();
recvQueue.resize(0);
return a;
int ret = SSL_accept(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else
return Bad;
}
else if(ret == 0)
return Bad;
return Good;
}
void sslReadAll()
int doHandshake()
{
QByteArray a;
while(1) {
a.resize(4096);
int x = SSL_read(ssl, a.data(), a.size());
if(x <= 0)
int ret = SSL_do_handshake(ssl);
if(ret < 0) {
int x = SSL_get_error(ssl, ret);
if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
return TryAgain;
else
return Bad;
}
else if(ret == 0)
return Bad;
return Good;
}
QCA_CertContext *peerCertificate() const
{
return cc.clone();
}
int validityResult() const
{
return vr;
}
int resultToCV(int ret) const
{
int rc;
switch(ret) {
case X509_V_ERR_CERT_REJECTED:
rc = QCA::TLS::Rejected;
break;
case X509_V_ERR_CERT_UNTRUSTED:
rc = QCA::TLS::Untrusted;
break;
case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
case X509_V_ERR_CERT_SIGNATURE_FAILURE:
case X509_V_ERR_CRL_SIGNATURE_FAILURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
rc = QCA::TLS::SignatureFailed;
break;
case X509_V_ERR_INVALID_CA:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
rc = QCA::TLS::InvalidCA;
break;
case X509_V_ERR_INVALID_PURPOSE:
rc = QCA::TLS::InvalidPurpose;
break;
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
rc = QCA::TLS::SelfSigned;
break;
case X509_V_ERR_CERT_REVOKED:
rc = QCA::TLS::Revoked;
break;
case X509_V_ERR_PATH_LENGTH_EXCEEDED:
rc = QCA::TLS::PathLengthExceeded;
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
case X509_V_ERR_CRL_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
rc = QCA::TLS::Expired;
break;
case X509_V_ERR_APPLICATION_VERIFICATION:
case X509_V_ERR_OUT_OF_MEM:
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_CERT_CHAIN_TOO_LONG:
default:
rc = QCA::TLS::Unknown;
break;
if(x != (int)a.size())
a.resize(x);
appendArray(&recvQueue, a);
}
return rc;
}
void processSendQueue()
{
if(sendQueue.size() > 0) {
// since we are using memory BIOs, the whole thing can be written successfully
SSL_write(ssl, sendQueue.data(), sendQueue.size());
sendQueue.resize(0);
sslUpdate();
}
}
bool serv;
int mode;
QByteArray sendQueue, recvQueue;
CertContext *cert;
RSAKeyContext *key;
SSL *ssl;
SSL_METHOD *method;
SSL_CTX *context;
BIO *rbio, *wbio;
QString host;
CertContext cc;
int vr;
};
class QCAOpenSSL : public QCAProvider
@ -1378,7 +1345,7 @@ public:
#endif
QCA::CAP_RSA |
QCA::CAP_X509 |
QCA::CAP_SSL;
QCA::CAP_TLS;
return caps;
}
@ -1402,8 +1369,8 @@ public:
return new RSAKeyContext;
else if(cap == QCA::CAP_X509)
return new CertContext;
else if(cap == QCA::CAP_SSL)
return new SSLContext;
else if(cap == QCA::CAP_TLS)
return new TLSContext;
return 0;
}
};
@ -1417,4 +1384,4 @@ QCAProvider *createProviderOpenSSL()
return (new QCAOpenSSL);
}
#include"qcaopenssl.moc"
//#include"qcaopenssl.moc"

@ -38,9 +38,10 @@ public:
connect(sasl, SIGNAL(clientFirstStep(const QString &, const QByteArray *)), SLOT(sasl_clientFirstStep(const QString &, const QByteArray *)));
connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
connect(sasl, SIGNAL(needParams(bool, bool, bool, bool)), SLOT(sasl_needParams(bool, bool, bool, bool)));
connect(sasl, SIGNAL(authenticated(bool)), SLOT(sasl_authenticated(bool)));
connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
}
~ClientTest()
@ -59,7 +60,7 @@ public:
if(!user.isEmpty()) {
sasl->setUsername(user);
sasl->setAuthname(user);
sasl->setAuthzid(user);
}
if(!pass.isEmpty())
sasl->setPassword(pass);
@ -136,16 +137,16 @@ private slots:
sendLine(line);
}
void sasl_needParams(bool auth, bool user, bool pass, bool realm)
void sasl_needParams(bool user, bool authzid, bool pass, bool realm)
{
QString username;
if(auth || user)
if(user || authzid)
username = prompt("Username:");
if(user) {
sasl->setUsername(username);
}
if(auth) {
sasl->setAuthname(username);
if(authzid) {
sasl->setAuthzid(username);
}
if(pass) {
sasl->setPassword(prompt("Password (not hidden!) :"));
@ -156,13 +157,9 @@ private slots:
sasl->continueAfterParams();
}
void sasl_authenticated(bool ok)
void sasl_authenticated()
{
printf("SASL %s!\n", ok ? "success" : "failed");
if(!ok) {
quit();
return;
}
printf("SASL success!\n");
printf("SSF: %d\n", sasl->ssf());
}
@ -181,6 +178,13 @@ private slots:
sock->writeBlock(a.data(), a.size());
}
void sasl_error(int)
{
printf("SASL error!\n");
quit();
return;
}
private:
QSocket *sock;
QCA::SASL *sasl;
@ -218,6 +222,7 @@ private:
++mode;
// kick off the client
sasl->setAllowAnonymous(false);
if(!sasl->startClient(PROTO_NAME, host, mechlist)) {
printf("Error starting client!\n");
quit();
@ -332,10 +337,12 @@ public:
connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
sasl = new QCA::SASL;
connect(sasl, SIGNAL(authCheck(const QString &, const QString &)), SLOT(sasl_authCheck(const QString &, const QString &)));
connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
connect(sasl, SIGNAL(authenticated(bool)), SLOT(sasl_authenticated(bool)));
connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
sock->setSocket(s);
mode = 0;
@ -415,18 +422,19 @@ private slots:
sendLine(line);
}
void sasl_authenticated(bool ok)
void sasl_authCheck(const QString &user, const QString &authzid)
{
if(ok)
sendLine("A");
else
sendLine("E");
printf("Authentication %s.\n", ok ? "success" : "failed");
if(ok) {
++mode;
printf("SSF: %d\n", sasl->ssf());
sendLine(str);
}
printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.latin1(), authzid.latin1());
sasl->continueAfterAuthCheck();
}
void sasl_authenticated()
{
sendLine("A");
printf("Authentication success.\n");
++mode;
printf("SSF: %d\n", sasl->ssf());
sendLine(str);
}
void sasl_readyRead()
@ -445,6 +453,19 @@ private slots:
sock->writeBlock(a.data(), a.size());
}
void sasl_error(int x)
{
if(x == QCA::SASL::ErrAuth) {
sendLine("E");
printf("Authentication failed.\n");
close();
}
else {
printf("SASL security layer error!\n");
close();
}
}
private:
QSocket *sock;
QCA::SASL *sasl;

@ -258,9 +258,13 @@ Cipher::~Cipher()
delete d;
}
QByteArray Cipher::dyn_generateKey() const
QByteArray Cipher::dyn_generateKey(int size) const
{
QByteArray buf(d->c->keySize());
QByteArray buf;
if(size != -1)
buf.resize(size);
else
buf.resize(d->c->keySize());
if(!d->c->generateKey(buf.data()))
return QByteArray();
return buf;
@ -710,14 +714,14 @@ bool Cert::fromPEM(const QString &str)
//----------------------------------------------------------------------------
// SSL
// TLS
//----------------------------------------------------------------------------
class SSL::Private
class TLS::Private
{
public:
Private()
{
c = (QCA_SSLContext *)getContext(CAP_SSL);
c = (QCA_TLSContext *)getContext(CAP_TLS);
}
~Private()
@ -725,95 +729,179 @@ public:
delete c;
}
void reset()
{
handshaken = false;
in.resize(0);
out.resize(0);
from_net.resize(0);
to_net.resize(0);
host = "";
hostMismatch = false;
}
void appendArray(QByteArray *a, const QByteArray &b)
{
int oldsize = a->size();
a->resize(oldsize + b.size());
memcpy(a->data() + oldsize, b.data(), b.size());
}
Cert cert;
QCA_SSLContext *c;
QCA_TLSContext *c;
QByteArray in, out, to_net, from_net;
bool handshaken;
QString host;
bool hostMismatch;
Cert ourCert;
RSAKey ourKey;
QPtrList<QCA_CertContext> store;
};
SSL::SSL(QObject *parent)
TLS::TLS(QObject *parent)
:QObject(parent)
{
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()
TLS::~TLS()
{
delete d;
}
bool SSL::startClient(const QString &host, const QPtrList<Cert> &store)
void TLS::setCertificate(const Cert &cert, const RSAKey &key)
{
d->cert = Cert();
d->ourCert = cert;
d->ourKey = key;
}
void TLS::setCertificateStore(const QPtrList<Cert> &store)
{
// convert the cert list into a context list
QPtrList<QCA_CertContext> list;
d->store.clear();
QPtrListIterator<Cert> it(store);
for(Cert *cert; (cert = it.current()); ++it)
list.append(cert->d->c);
d->store.append(cert->d->c);
}
// begin!
if(!d->c->startClient(host, list))
bool TLS::startClient(const QString &host)
{
d->reset();
d->host = host;
if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
return false;
QTimer::singleShot(0, this, SLOT(update()));
return true;
}
bool SSL::startServer(const Cert &cert, const RSAKey &key)
bool TLS::startServer()
{
if(!d->c->startServer(*cert.d->c, *key.d->c))
d->reset();
if(!d->c->startServer(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
return false;
QTimer::singleShot(0, this, SLOT(update()));
return true;
}
void SSL::write(const QByteArray &a)
void TLS::write(const QByteArray &a)
{
d->c->write(a);
d->appendArray(&d->out, a);
update();
}
QByteArray SSL::read()
QByteArray TLS::read()
{
return d->c->read();
QByteArray a = d->in.copy();
d->in.resize(0);
return a;
}
void SSL::writeIncoming(const QByteArray &a)
void TLS::writeIncoming(const QByteArray &a)
{
d->c->writeIncoming(a);
d->appendArray(&d->from_net, a);
update();
}
QByteArray SSL::readOutgoing()
QByteArray TLS::readOutgoing()
{
return d->c->readOutgoing();
QByteArray a = d->to_net.copy();
d->to_net.resize(0);
return a;
}
const Cert & SSL::peerCertificate() const
const Cert & TLS::peerCertificate() const
{
return d->cert;
}
int SSL::certificateValidityResult() const
int TLS::certificateValidityResult() const
{
return d->c->validityResult();
if(d->hostMismatch)
return QCA::TLS::HostMismatch;
else
return d->c->validityResult();
}
void SSL::ctx_handshaken(bool b)
void TLS::update()
{
if(b) {
// read the cert
QCA_CertContext *cc = d->c->peerCertificate();
d->cert.fromContext(cc);
bool force_read = false;
if(!d->handshaken) {
QByteArray a;
int r = d->c->handshake(d->from_net, &a);
d->from_net.resize(0);
if(r == QCA_TLSContext::Error) {
error(ErrHandshake);
return;
}
d->appendArray(&d->to_net, a);
if(r == QCA_TLSContext::Success) {
QCA_CertContext *cc = d->c->peerCertificate();
if(cc && !d->host.isEmpty() && d->c->validityResult() == QCA::TLS::Valid) {
if(!cc->matchesAddress(d->host))
d->hostMismatch = true;
}
d->cert.fromContext(cc);
d->handshaken = true;
handshaken();
// there is a teeny tiny possibility that incoming data awaits. let us get it.
force_read = true;
}
}
handshaken(b);
}
void SSL::ctx_readyRead()
{
readyRead();
}
if(d->handshaken) {
if(!d->out.isEmpty()) {
QByteArray a;
bool ok = d->c->encode(d->out, &a);
d->out.resize(0);
if(!ok) {
error(ErrCrypt);
return;
}
d->appendArray(&d->to_net, a);
}
if(!d->from_net.isEmpty() || force_read) {
QByteArray a, b;
bool ok = d->c->decode(d->from_net, &a, &b);
d->from_net.resize(0);
if(!ok) {
error(ErrCrypt);
return;
}
d->appendArray(&d->in, a);
d->appendArray(&d->to_net, b);
}
void SSL::ctx_readyReadOutgoing()
{
readyReadOutgoing();
if(!d->in.isEmpty())
readyRead();
}
if(!d->to_net.isEmpty())
readyReadOutgoing();
}
@ -850,6 +938,7 @@ public:
QHostAddress localAddr, remoteAddr;
int localPort, remotePort;
QByteArray stepData;
bool allowCSF;
bool first, server;
QByteArray inbuf, outbuf;
@ -962,7 +1051,7 @@ void SASL::setRemoteAddr(const QHostAddress &addr, Q_UINT16 port)
d->remotePort = port;
}
bool SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist)
bool SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, bool allowClientSendFirst)
{
QCA_SASLHostPort la, ra;
if(d->localPort != -1) {
@ -974,6 +1063,7 @@ bool SASL::startClient(const QString &service, const QString &host, const QStrin
ra.port = d->remotePort;
}
d->allowCSF = allowClientSendFirst;
d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
d->setSecurityProps();
@ -1024,13 +1114,13 @@ void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
void SASL::handleServerFirstStep(int r)
{
if(r == QCA_SASLContext::Success)
authenticated(true);
authenticated();
else if(r == QCA_SASLContext::Continue)
nextStep(d->c->result());
else if(r == QCA_SASLContext::AuthCheck)
tryAgain();
else
authenticated(false);
error(ErrAuth);
}
void SASL::putStep(const QByteArray &stepData)
@ -1039,14 +1129,14 @@ void SASL::putStep(const QByteArray &stepData)
tryAgain();
}
void SASL::setAuthname(const QString &auth)
{
d->c->setClientParams(&auth, 0, 0, 0);
}
void SASL::setUsername(const QString &user)
{
d->c->setClientParams(0, &user, 0, 0);
d->c->setClientParams(&user, 0, 0, 0);
}
void SASL::setAuthzid(const QString &authzid)
{
d->c->setClientParams(0, &authzid, 0, 0);
}
void SASL::setPassword(const QString &pass)
@ -1064,6 +1154,11 @@ void SASL::continueAfterParams()
tryAgain();
}
void SASL::continueAfterAuthCheck()
{
tryAgain();
}
void SASL::tryAgain()
{
int r;
@ -1078,7 +1173,7 @@ void SASL::tryAgain()
}
if(r == QCA_SASLContext::Error) {
authenticated(false);
error(ErrAuth);
return;
}
else if(r == QCA_SASLContext::Continue) {
@ -1087,27 +1182,27 @@ void SASL::tryAgain()
return;
}
else if(r == QCA_SASLContext::AuthCheck) {
// TODO: authcheck
tryAgain();
authCheck(d->c->username(), d->c->authzid());
return;
}
}
else {
if(d->first) {
if(!d->tried) {
r = d->c->clientFirstStep(true);
r = d->c->clientFirstStep(d->allowCSF);
d->tried = true;
}
else
r = d->c->tryAgain();
if(r == QCA_SASLContext::Error) {
authenticated(false);
error(ErrAuth);
return;
}
else if(r == QCA_SASLContext::NeedParams) {
//d->tried = false;
QCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.auth, np.user, np.pass, np.realm);
needParams(np.user, np.authzid, np.pass, np.realm);
return;
}
@ -1127,13 +1222,13 @@ void SASL::tryAgain()
r = d->c->tryAgain();
if(r == QCA_SASLContext::Error) {
authenticated(false);
error(ErrAuth);
return;
}
else if(r == QCA_SASLContext::NeedParams) {
//d->tried = false;
QCA_SASLNeedParams np = d->c->clientParamsNeeded();
needParams(np.auth, np.user, np.pass, np.realm);
needParams(np.user, np.authzid, np.pass, np.realm);
return;
}
d->tried = false;
@ -1145,9 +1240,9 @@ void SASL::tryAgain()
}
if(r == QCA_SASLContext::Success)
authenticated(true);
authenticated();
else if(r == QCA_SASLContext::Error)
authenticated(false);
error(ErrAuth);
}
int SASL::ssf() const
@ -1159,7 +1254,7 @@ void SASL::write(const QByteArray &a)
{
QByteArray b;
if(!d->c->encode(a, &b)) {
error();
error(ErrCrypt);
return;
}
int oldsize = d->outbuf.size();
@ -1179,7 +1274,7 @@ void SASL::writeIncoming(const QByteArray &a)
{
QByteArray b;
if(!d->c->decode(a, &b)) {
error();
error(ErrCrypt);
return;
}
int oldsize = d->inbuf.size();

@ -27,7 +27,7 @@ namespace QCA
CAP_AES256 = 0x0040,
CAP_RSA = 0x0080,
CAP_X509 = 0x0100,
CAP_SSL = 0x0200,
CAP_TLS = 0x0200,
CAP_SASL = 0x0400,
};
@ -104,7 +104,7 @@ namespace QCA
Cipher & operator=(const Cipher &);
~Cipher();
QByteArray dyn_generateKey() const;
QByteArray dyn_generateKey(int size=-1) const;
QByteArray dyn_generateIV() const;
void reset(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad=true);
bool update(const QByteArray &a);
@ -124,10 +124,10 @@ namespace QCA
public:
CipherStatic<T>() {}
static QByteArray generateKey()
static QByteArray generateKey(int size=-1)
{
T obj;
return obj.dyn_generateKey();
return obj.dyn_generateKey(size);
}
static QByteArray generateIV()
@ -206,7 +206,7 @@ namespace QCA
Private *d;
friend class RSA;
friend class SSL;
friend class TLS;
bool encrypt(const QByteArray &a, QByteArray *out, bool oaep) const;
bool decrypt(const QByteArray &a, QByteArray *out, bool oaep) const;
bool generate(unsigned int bits);
@ -259,15 +259,15 @@ namespace QCA
class Private;
Private *d;
friend class SSL;
friend class TLS;
void fromContext(QCA_CertContext *);
};
class SSL : public QObject
class TLS : public QObject
{
Q_OBJECT
public:
enum {
enum Validity {
NoCert,
Valid,
HostMismatch,
@ -282,13 +282,16 @@ namespace QCA
Expired,
Unknown
};
enum Error { ErrHandshake, ErrCrypt };
SSL(QObject *parent=0);
~SSL();
TLS(QObject *parent=0);
~TLS();
// note: store must persist until SSL object is deleted!
bool startClient(const QString &host="", const QPtrList<Cert> &store=QPtrList<Cert>());
bool startServer(const Cert &cert, const RSAKey &key);
void setCertificate(const Cert &cert, const RSAKey &key);
void setCertificateStore(const QPtrList<Cert> &store); // note: store must persist
bool startClient(const QString &host="");
bool startServer();
// plain (application side)
void write(const QByteArray &a);
@ -303,26 +306,24 @@ namespace QCA
int certificateValidityResult() const;
signals:
void handshaken(bool);
void handshaken();
void readyRead();
void readyReadOutgoing();
void error(int);
private slots:
void ctx_handshaken(bool);
void ctx_readyRead();
void ctx_readyReadOutgoing();
void update();
private:
class Private;
Private *d;
};
// TODO: server authcheck
// security layer
class SASL : public QObject
{
Q_OBJECT
public:
enum Error { ErrAuth, ErrCrypt };
SASL(QObject *parent=0);
~SASL();
@ -348,18 +349,19 @@ namespace QCA
void setRemoteAddr(const QHostAddress &addr, Q_UINT16 port);
// initialize
bool startClient(const QString &service, const QString &host, const QStringList &mechlist);
bool startClient(const QString &service, const QString &host, const QStringList &mechlist, bool allowClientSendFirst=true);
bool startServer(const QString &service, const QString &host, const QString &realm, QStringList *mechlist);
// authentication
void putStep(const QByteArray &stepData);
void putServerFirstStep(const QString &mech);
void putServerFirstStep(const QString &mech, const QByteArray &clientInit);
void setAuthname(const QString &auth);
void setUsername(const QString &user);
void setAuthzid(const QString &auth);
void setPassword(const QString &pass);
void setRealm(const QString &realm);
void continueAfterParams();
void continueAfterAuthCheck();
// security layer
int ssf() const;
@ -372,13 +374,16 @@ namespace QCA
// for authentication
void clientFirstStep(const QString &mech, const QByteArray *clientInit);
void nextStep(const QByteArray &stepData);
void needParams(bool auth, bool user, bool pass, bool realm);
void authenticated(bool);
void needParams(bool user, bool authzid, bool pass, bool realm);
void authCheck(const QString &user, const QString &authzid);
void authenticated();
// for security layer
void readyRead();
void readyReadOutgoing();
void error();
// error
void error(int);
private slots:
void tryAgain();

@ -96,28 +96,25 @@ public:
virtual QValueList<QCA_CertProperty> issuer() const=0;
virtual QDateTime notBefore() const=0;
virtual QDateTime notAfter() const=0;
virtual bool matchesAddress(const QString &realHost) const=0;
};
class QCA_SSLContext : public QObject
class QCA_TLSContext
{
Q_OBJECT
public:
virtual ~QCA_SSLContext() {}
enum Result { Success, Error, Continue };
virtual ~QCA_TLSContext() {}
virtual bool startClient(const QString &host, const QPtrList<QCA_CertContext> &store)=0;
virtual bool startServer(const QCA_CertContext &cert, const QCA_RSAKeyContext &key)=0;
virtual void reset()=0;
virtual bool startClient(const QPtrList<QCA_CertContext> &store, const QCA_CertContext &cert, const QCA_RSAKeyContext &key)=0;
virtual bool startServer(const QPtrList<QCA_CertContext> &store, const QCA_CertContext &cert, const QCA_RSAKeyContext &key)=0;
virtual int handshake(const QByteArray &in, QByteArray *out)=0;
virtual bool encode(const QByteArray &plain, QByteArray *to_net)=0;
virtual bool decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net)=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();
};
struct QCA_SASLHostPort
@ -128,13 +125,13 @@ struct QCA_SASLHostPort
struct QCA_SASLNeedParams
{
bool auth, user, pass, realm;
bool user, authzid, pass, realm;
};
class QCA_SASLContext
{
public:
enum { Success, Error, NeedParams, AuthCheck, Continue };
enum Result { Success, Error, NeedParams, AuthCheck, Continue };
virtual ~QCA_SASLContext() {}
// common
@ -151,9 +148,9 @@ public:
// get / set params
virtual QCA_SASLNeedParams clientParamsNeeded() const=0;
virtual void setClientParams(const QString *auth, const QString *user, const QString *pass, const QString *realm)=0;
virtual QString authname() const=0;
virtual void setClientParams(const QString *user, const QString *authzid, const QString *pass, const QString *realm)=0;
virtual QString username() const=0;
virtual QString authzid() const=0;
// continue steps
virtual int nextStep(const QByteArray &in)=0;

@ -57,10 +57,11 @@ public:
connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
ssl = new QCA::SSL;
connect(ssl, SIGNAL(handshaken(bool)), SLOT(ssl_handshaken(bool)));
ssl = new QCA::TLS;
connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
connect(ssl, SIGNAL(readyReadOutgoing()), SLOT(ssl_readyReadOutgoing()));
connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int)));
cert.fromPEM(pemdata_cert);
privkey.fromPEM(pemdata_privkey);
@ -100,7 +101,8 @@ public:
}
sock->setSocket(s);
printf("Connection received! Starting TLS handshake...\n");
ssl->startServer(cert, privkey);
ssl->setCertificate(cert, privkey);
ssl->startServer();
}
signals:
@ -139,15 +141,9 @@ private slots:
printf("Socket error.\n");
}
void ssl_handshaken(bool b)
void ssl_handshaken()
{
if(b) {
printf("Successful SSL handshake. Waiting for newline.\n");
}
else {
printf("SSL Handshake Error! Closing.\n");
sock->close();
}
printf("Successful SSL handshake. Waiting for newline.\n");
}
void ssl_readyRead()
@ -180,10 +176,22 @@ private slots:
sock->writeBlock(a.data(), a.size());
}
void ssl_error(int x)
{
if(x == QCA::TLS::ErrHandshake) {
printf("SSL Handshake Error! Closing.\n");
sock->close();
}
else {
printf("SSL Error! Closing.\n");
sock->close();
}
}
private:
int port;
QSocket *sock;
QCA::SSL *ssl;
QCA::TLS *ssl;
QCA::Cert cert;
QCA::RSAKey privkey;
@ -198,8 +206,8 @@ int main(int argc, char **argv)
QApplication app(argc, argv, false);
int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
if(!QCA::isSupported(QCA::CAP_SSL)) {
printf("SSL not supported!\n");
if(!QCA::isSupported(QCA::CAP_TLS)) {
printf("TLS not supported!\n");
return 1;
}

@ -72,42 +72,42 @@ QString resultToString(int result)
{
QString s;
switch(result) {
case QCA::SSL::NoCert:
case QCA::TLS::NoCert:
s = QObject::tr("No certificate presented.");
break;
case QCA::SSL::Valid:
case QCA::TLS::Valid:
break;
case QCA::SSL::HostMismatch:
case QCA::TLS::HostMismatch:
s = QObject::tr("Hostname mismatch.");
break;
case QCA::SSL::Rejected:
case QCA::TLS::Rejected:
s = QObject::tr("Root CA rejects the specified purpose.");
break;
case QCA::SSL::Untrusted:
case QCA::TLS::Untrusted:
s = QObject::tr("Not trusted for the specified purpose.");
break;
case QCA::SSL::SignatureFailed:
case QCA::TLS::SignatureFailed:
s = QObject::tr("Invalid signature.");
break;
case QCA::SSL::InvalidCA:
case QCA::TLS::InvalidCA:
s = QObject::tr("Invalid CA certificate.");
break;
case QCA::SSL::InvalidPurpose:
case QCA::TLS::InvalidPurpose:
s = QObject::tr("Invalid certificate purpose.");
break;
case QCA::SSL::SelfSigned:
case QCA::TLS::SelfSigned:
s = QObject::tr("Certificate is self-signed.");
break;
case QCA::SSL::Revoked:
case QCA::TLS::Revoked:
s = QObject::tr("Certificate has been revoked.");
break;
case QCA::SSL::PathLengthExceeded:
case QCA::TLS::PathLengthExceeded:
s = QObject::tr("Maximum cert chain length exceeded.");
break;
case QCA::SSL::Expired:
case QCA::TLS::Expired:
s = QObject::tr("Certificate has expired.");
break;
case QCA::SSL::Unknown:
case QCA::TLS::Unknown:
default:
s = QObject::tr("General validation error.");
break;
@ -127,13 +127,14 @@ public:
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
ssl = new QCA::SSL;
connect(ssl, SIGNAL(handshaken(bool)), SLOT(ssl_handshaken(bool)));
ssl = new QCA::TLS;
connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
connect(ssl, SIGNAL(readyReadOutgoing()), SLOT(ssl_readyReadOutgoing()));
connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int)));
rootCerts.setAutoDelete(true);
rootCerts = getRootCerts("/usr/share/psi/certs/rootcert.xml");
rootCerts = getRootCerts("/usr/local/share/psi/certs/rootcert.xml");
}
~SecureTest()
@ -166,7 +167,8 @@ private slots:
void sock_connected()
{
printf("Connected, starting TLS handshake...\n");
ssl->startClient(host, rootCerts);
ssl->setCertificateStore(rootCerts);
ssl->startClient(host);
}
void sock_readyRead()
@ -190,31 +192,25 @@ private slots:
quit();
}
void ssl_handshaken(bool b)
void ssl_handshaken()
{
if(b) {
cert = ssl->peerCertificate();
int vr = ssl->certificateValidityResult();
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("Successful SSL handshake.\n");
if(!cert.isNull())
showCertInfo(cert);
if(vr == QCA::TLS::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();
}
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);
}
void ssl_readyRead()
@ -232,10 +228,22 @@ private slots:
sock->writeBlock(a.data(), a.size());
}
void ssl_error(int x)
{
if(x == QCA::TLS::ErrHandshake) {
printf("SSL Handshake Error!\n");
quit();
}
else {
printf("SSL Error!\n");
quit();
}
}
private:
QString host;
QSocket *sock;
QCA::SSL *ssl;
QCA::TLS *ssl;
QCA::Cert cert;
QPtrList<QCA::Cert> rootCerts;
};
@ -247,8 +255,8 @@ int main(int argc, char **argv)
QApplication app(argc, argv, false);
QString host = argc > 1 ? argv[1] : "andbit.net";
if(!QCA::isSupported(QCA::CAP_SSL)) {
printf("SSL not supported!\n");
if(!QCA::isSupported(QCA::CAP_TLS)) {
printf("TLS not supported!\n");
return 1;
}