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:
parent
d13a80de4e
commit
6c723d8ee5
34
README
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
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"
|
||||
|
69
sasltest.cpp
69
sasltest.cpp
@ -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;
|
||||
|
225
src/qca.cpp
225
src/qca.cpp
@ -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();
|
||||
|
53
src/qca.h
53
src/qca.h
@ -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;
|
||||
}
|
||||
|
||||
|
92
ssltest.cpp
92
ssltest.cpp
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user