summaryrefslogtreecommitdiffstats
path: root/qca-tls.cpp
diff options
context:
space:
mode:
authorgregory guy <gregory-tde@laposte.net>2020-01-02 15:12:40 +0100
committerSlávek Banko <slavek.banko@axis.cz>2020-01-22 16:16:32 +0100
commita2c0e6c98197215ac788982fbf5b236888eef79e (patch)
tree7ea36879375d9ad579fcdf226a605a36232e827b /qca-tls.cpp
parent9cd1493c36e94b9bfd36e35bc197ecf87634970e (diff)
downloadtqca-tls-a2c0e6c98197215ac788982fbf5b236888eef79e.tar.gz
tqca-tls-a2c0e6c98197215ac788982fbf5b236888eef79e.zip
Conversion to the cmake building system.
Signed-off-by: gregory guy <gregory-tde@laposte.net>
Diffstat (limited to 'qca-tls.cpp')
-rw-r--r--qca-tls.cpp1510
1 files changed, 0 insertions, 1510 deletions
diff --git a/qca-tls.cpp b/qca-tls.cpp
deleted file mode 100644
index b5080ed..0000000
--- a/qca-tls.cpp
+++ /dev/null
@@ -1,1510 +0,0 @@
-/*
- * qca-tls.cpp - TLS plugin for TQCA
- * Copyright (C) 2003 Justin Karneges
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include"qca-tls.h"
-
-#include<tqregexp.h>
-
-#include<openssl/sha.h>
-#include<openssl/md5.h>
-#include<openssl/evp.h>
-#include<openssl/bio.h>
-#include<openssl/pem.h>
-#include<openssl/rsa.h>
-#include<openssl/x509.h>
-#include<openssl/x509v3.h>
-#include<openssl/ssl.h>
-#include<openssl/err.h>
-#include<openssl/rand.h>
-
-#ifndef OSSL_097
-#define NO_AES
-#endif
-
-static TQByteArray lib_randomArray(int size)
-{
- if(RAND_status() == 0) {
- srand(time(NULL));
- char buf[128];
- for(int n = 0; n < 128; ++n)
- buf[n] = rand();
- RAND_seed(buf, 128);
- }
- TQByteArray a(size);
- RAND_bytes((unsigned char *)a.data(), a.size());
- return a;
-}
-
-static bool lib_generateKeyIV(const EVP_CIPHER *_type, const TQByteArray &data, const TQByteArray &salt, TQByteArray *key, TQByteArray *iv, int keysize=-1)
-{
- TQByteArray k, i;
- unsigned char *kp = 0;
- unsigned char *ip = 0;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- EVP_CIPHER type = *_type;
- EVP_CIPHER *loctype = &type;
- if(keysize != -1)
- type.key_len = keysize;
-#else
- EVP_CIPHER *loctype = EVP_CIPHER_meth_dup(_type);
- Q_UNUSED(keysize)
-#endif
- if(key) {
- k.resize(EVP_CIPHER_key_length(loctype));
- kp = (unsigned char *)k.data();
- }
- if(iv) {
- i.resize(EVP_CIPHER_iv_length(loctype));
- ip = (unsigned char *)i.data();
- }
- int res = EVP_BytesToKey(loctype, EVP_sha1(), (unsigned char *)salt.data(), (unsigned char *)data.data(), data.size(), 1, kp, ip);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
- EVP_CIPHER_meth_free(loctype);
-#endif
- if (!res)
- return false;
- if(key)
- *key = k;
- if(iv)
- *iv = i;
- return true;
-}
-
-static void appendArray(TQByteArray *a, const TQByteArray &b)
-{
- int oldsize = a->size();
- a->resize(oldsize + b.size());
- memcpy(a->data() + oldsize, b.data(), b.size());
-}
-
-static TQByteArray bio2buf(BIO *b)
-{
- TQByteArray buf;
- while(1) {
- char block[1024];
- int ret = BIO_read(b, block, 1024);
- int oldsize = buf.size();
- buf.resize(oldsize + ret);
- memcpy(buf.data() + oldsize, block, ret);
- if(ret != 1024)
- break;
- }
- BIO_free(b);
- return buf;
-}
-
-class SHA1Context : public TQCA_HashContext
-{
-public:
- SHA1Context()
- {
- reset();
- }
-
- TQCA_HashContext *clone()
- {
- return new SHA1Context(*this);
- }
-
- void reset()
- {
- SHA1_Init(&c);
- }
-
- void update(const char *in, unsigned int len)
- {
- SHA1_Update(&c, in, len);
- }
-
- void final(TQByteArray *out)
- {
- TQByteArray buf(20);
- SHA1_Final((unsigned char *)buf.data(), &c);
- *out = buf;
- }
-
- SHA_CTX c;
-};
-
-class MD5Context : public TQCA_HashContext
-{
-public:
- MD5Context()
- {
- reset();
- }
-
- TQCA_HashContext *clone()
- {
- return new MD5Context(*this);
- }
-
- void reset()
- {
- MD5_Init(&c);
- }
-
- void update(const char *in, unsigned int len)
- {
- MD5_Update(&c, in, len);
- }
-
- void final(TQByteArray *out)
- {
- TQByteArray buf(16);
- MD5_Final((unsigned char *)buf.data(), &c);
- *out = buf;
- }
-
- MD5_CTX c;
-};
-
-class EVPCipherContext : public TQCA_CipherContext
-{
-public:
- EVPCipherContext()
- {
- type = 0;
- }
-
- virtual ~EVPCipherContext()
- {
- if(type) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- EVP_CIPHER_CTX_cleanup(c);
- OPENSSL_free(c);
-#else
- EVP_CIPHER_CTX_free(c);
-#endif
- type = 0;
- }
- }
-
- TQCA_CipherContext *clone()
- {
- EVPCipherContext *cc = cloneSelf();
- cc->r = r.copy();
- return cc;
- }
-
- virtual EVPCipherContext *cloneSelf() const=0;
- virtual const EVP_CIPHER *getType(int mode) const=0;
-
- int keySize() { return EVP_CIPHER_key_length(getType(TQCA::CBC)); }
- int blockSize() { return EVP_CIPHER_block_size(getType(TQCA::CBC)); }
-
- bool generateKey(char *out, int keysize)
- {
- TQByteArray a;
- if(!lib_generateKeyIV(getType(TQCA::CBC), lib_randomArray(128), lib_randomArray(2), &a, 0, keysize))
- return false;
- memcpy(out, a.data(), a.size());
- return true;
- }
-
- bool generateIV(char *out)
- {
- TQByteArray a;
- if(!lib_generateKeyIV(getType(TQCA::CBC), lib_randomArray(128), lib_randomArray(2), 0, &a))
- return false;
- memcpy(out, a.data(), a.size());
- return true;
- }
-
- bool setup(int _dir, int mode, const char *key, int keysize, const char *iv, bool _pad)
- {
- dir = _dir;
- pad = _pad;
- type = getType(mode);
- r.resize(0);
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
- c = (EVP_CIPHER_CTX*)OPENSSL_malloc(sizeof(EVP_CIPHER_CTX));
- EVP_CIPHER_CTX_init(c);
-#else
- c = EVP_CIPHER_CTX_new();
-#endif
-
- if(dir == TQCA::Encrypt) {
- if(!EVP_EncryptInit(c, type, NULL, NULL))
- return false;
- if(keysize != EVP_CIPHER_key_length(type))
- EVP_CIPHER_CTX_set_key_length(c, keysize);
- if(!EVP_EncryptInit(c, NULL, (unsigned char *)key, (unsigned char *)iv))
- return false;
- }
- else {
- if(!EVP_DecryptInit(c, type, NULL, NULL))
- return false;
- if(keysize != EVP_CIPHER_key_length(type))
- EVP_CIPHER_CTX_set_key_length(c, keysize);
- if(!EVP_DecryptInit(c, NULL, (unsigned char *)key, (unsigned char *)iv))
- return false;
- }
- return true;
- }
-
- bool update(const char *in, unsigned int len)
- {
- TQByteArray result(len + EVP_CIPHER_block_size(type));
- int olen;
- if(dir == TQCA::Encrypt || !pad) {
- if(!EVP_EncryptUpdate(c, (unsigned char *)result.data(), &olen, (unsigned char *)in, len))
- return false;
- }
- else {
- if(!EVP_DecryptUpdate(c, (unsigned char *)result.data(), &olen, (unsigned char *)in, len))
- return false;
- }
- result.resize(olen);
- appendArray(&r, result);
- return true;
- }
-
- bool final(TQByteArray *out)
- {
- if(pad) {
- TQByteArray result(EVP_CIPHER_block_size(type));
- int olen;
- if(dir == TQCA::Encrypt) {
- if(!EVP_EncryptFinal_ex(c, (unsigned char *)result.data(), &olen))
- return false;
- }
- else {
- if(!EVP_DecryptFinal_ex(c, (unsigned char *)result.data(), &olen))
- return false;
- }
- result.resize(olen);
- appendArray(&r, result);
- }
-
- *out = r.copy();
- r.resize(0);
- return true;
- }
-
- EVP_CIPHER_CTX *c;
- const EVP_CIPHER *type;
- TQByteArray r;
- int dir;
- bool pad;
-};
-
-class BlowFishContext : public EVPCipherContext
-{
-public:
- EVPCipherContext *cloneSelf() const { return new BlowFishContext(*this); }
- const EVP_CIPHER *getType(int mode) const
- {
- if(mode == TQCA::CBC)
- return EVP_bf_cbc();
- else if(mode == TQCA::CFB)
- return EVP_bf_cfb();
- else
- return 0;
- }
-};
-
-class TripleDESContext : public EVPCipherContext
-{
-public:
- EVPCipherContext *cloneSelf() const { return new TripleDESContext(*this); }
- const EVP_CIPHER *getType(int mode) const
- {
- if(mode == TQCA::CBC)
- return EVP_des_ede3_cbc();
- else if(mode == TQCA::CFB)
- return EVP_des_ede3_cfb();
- else
- return 0;
- }
-};
-
-#ifndef NO_AES
-class AES128Context : public EVPCipherContext
-{
-public:
- EVPCipherContext *cloneSelf() const { return new AES128Context(*this); }
- const EVP_CIPHER *getType(int mode) const
- {
- if(mode == TQCA::CBC)
- return EVP_aes_128_cbc();
- else if(mode == TQCA::CFB)
- return EVP_aes_128_cfb();
- else
- return 0;
- }
-};
-
-class AES256Context : public EVPCipherContext
-{
-public:
- EVPCipherContext *cloneSelf() const { return new AES256Context(*this); }
- const EVP_CIPHER *getType(int mode) const
- {
- if(mode == TQCA::CBC)
- return EVP_aes_256_cbc();
- else if(mode == TQCA::CFB)
- return EVP_aes_256_cfb();
- else
- return 0;
- }
-};
-#endif
-
-class RSAKeyContext : public TQCA_RSAKeyContext
-{
-public:
- RSAKeyContext()
- {
- pub = 0;
- sec = 0;
- }
-
- ~RSAKeyContext()
- {
- reset();
- }
-
- void reset()
- {
- if(pub) {
- RSA_free(pub);
- pub = 0;
- }
- if(sec) {
- RSA_free(sec);
- sec = 0;
- }
- }
-
- void separate(RSA *r, RSA **_pub, RSA **_sec)
- {
- // public
- unsigned char *buf, *p;
- int len = i2d_RSAPublicKey(r, NULL);
- if(len > 0) {
- buf = (unsigned char *)malloc(len);
- p = buf;
- i2d_RSAPublicKey(r, &p);
- p = buf;
-#ifdef OSSL_097
- *_pub = d2i_RSAPublicKey(NULL, (const unsigned char **)&p, len);
-#else
- *_pub = d2i_RSAPublicKey(NULL, (unsigned char **)&p, len);
-#endif
- free(buf);
- }
-
- len = i2d_RSAPrivateKey(r, NULL);
- if(len > 0) {
- buf = (unsigned char *)malloc(len);
- p = buf;
- i2d_RSAPrivateKey(r, &p);
- p = buf;
-#ifdef OSSL_097
- *_sec = d2i_RSAPrivateKey(NULL, (const unsigned char **)&p, len);
-#else
- *_sec = d2i_RSAPrivateKey(NULL, (unsigned char **)&p, len);
-#endif
- free(buf);
- }
- }
-
- bool isNull() const
- {
- if(!pub && !sec)
- return true;
- return false;
- }
-
- bool havePublic() const
- {
- return pub ? true : false;
- }
-
- bool havePrivate() const
- {
- return sec ? true : false;
- }
-
- bool createFromDER(const char *in, unsigned int len)
- {
- RSA *r;
- void *p;
-
- // private?
- p = (void *)in;
-#ifdef OSSL_097
- r = d2i_RSAPrivateKey(NULL, (const unsigned char **)&p, len);
-#else
- r = d2i_RSAPrivateKey(NULL, (unsigned char **)&p, len);
-#endif
- if(r) {
- reset();
-
- // private means both, I think, so separate them
- separate(r, &pub, &sec);
- return true;
- }
- else {
- // public?
- p = (void *)in;
-#ifdef OSSL_097
- r = d2i_RSAPublicKey(NULL, (const unsigned char **)&p, len);
-#else
- r = d2i_RSAPublicKey(NULL, (unsigned char **)&p, len);
-#endif
- if(!r) {
- // try this other public function, for whatever reason
- p = (void *)in;
- r = d2i_RSA_PUBKEY(NULL, (const unsigned char **)&p, len);
- }
- if(r) {
- if(pub) {
- RSA_free(pub);
- }
- pub = r;
- return true;
- }
- }
-
- return false;
- }
-
- bool createFromPEM(const char *in, unsigned int len)
- {
- BIO *bi;
-
- // private?
- bi = BIO_new(BIO_s_mem());
- BIO_write(bi, in, len);
- RSA *r = PEM_read_bio_RSAPrivateKey(bi, NULL, NULL, NULL);
- BIO_free(bi);
- if(r) {
- reset();
- separate(r, &pub, &sec);
- return true;
- }
- else {
- // public?
- bi = BIO_new(BIO_s_mem());
- BIO_write(bi, in, len);
- r = PEM_read_bio_RSAPublicKey(bi, NULL, NULL, NULL);
- BIO_free(bi);
- if(r) {
- if(pub) {
- RSA_free(pub);
- }
- pub = r;
- return true;
- }
- }
-
- return false;
- }
-
- bool createFromNative(void *in)
- {
- reset();
- separate((RSA *)in, &pub, &sec);
- return true;
- }
-
- bool generate(unsigned int bits)
- {
- BIGNUM *bign = BN_new();
- if (BN_set_word(bign, RSA_F4) != 1)
- {
- BN_free(bign);
- return false;
- }
- RSA *r = RSA_new();
- if(!r)
- {
- BN_free(bign);
- return false;
- }
- RSA_generate_key_ex(r, bits, bign, NULL);
- separate(r, &pub, &sec);
- RSA_free(r);
- BN_free(bign);
- return true;
- }
-
- TQCA_RSAKeyContext *clone() const
- {
- // deep copy
- RSAKeyContext *c = new RSAKeyContext;
- if(pub) {
- c->pub = RSAPublicKey_dup(pub);
- }
- if(sec) {
- c->sec = RSAPrivateKey_dup(sec);
- }
- return c;
- }
-
- bool toDER(TQByteArray *out, bool publicOnly)
- {
- if(sec && !publicOnly) {
- int len = i2d_RSAPrivateKey(sec, NULL);
- TQByteArray buf(len);
- unsigned char *p;
- p = (unsigned char *)buf.data();
- i2d_RSAPrivateKey(sec, &p);
- *out = buf;
- return true;
- }
- else if(pub) {
- int len = i2d_RSAPublicKey(pub, NULL);
- TQByteArray buf(len);
- unsigned char *p;
- p = (unsigned char *)buf.data();
- i2d_RSAPublicKey(pub, &p);
- *out = buf;
- return true;
- }
- else
- return false;
- }
-
- bool toPEM(TQByteArray *out, bool publicOnly)
- {
- if(sec && !publicOnly) {
- BIO *bo = BIO_new(BIO_s_mem());
- PEM_write_bio_RSAPrivateKey(bo, sec, NULL, NULL, 0, NULL, NULL);
- *out = bio2buf(bo);
- return true;
- }
- else if(pub) {
- BIO *bo = BIO_new(BIO_s_mem());
- PEM_write_bio_RSAPublicKey(bo, pub);
- *out = bio2buf(bo);
- return true;
- }
- else
- return false;
-
- }
-
- bool encrypt(const TQByteArray &in, TQByteArray *out, bool oaep)
- {
- if(!pub)
- return false;
-
- int size = RSA_size(pub);
- int flen = in.size();
- if(oaep) {
- if(flen >= size - 41)
- flen = size - 41;
- }
- else {
- if(flen >= size - 11)
- flen = size - 11;
- }
- TQByteArray result(size);
- unsigned char *from = (unsigned char *)in.data();
- unsigned char *to = (unsigned char *)result.data();
- int ret = RSA_public_encrypt(flen, from, to, pub, oaep ? RSA_PKCS1_OAEP_PADDING : RSA_PKCS1_PADDING);
- if(ret == -1)
- return false;
- result.resize(ret);
-
- *out = result;
- return true;
- }
-
- bool decrypt(const TQByteArray &in, TQByteArray *out, bool oaep)
- {
- if(!sec)
- return false;
-
- int size = RSA_size(sec);
- int flen = in.size();
- TQByteArray result(size);
- unsigned char *from = (unsigned char *)in.data();
- unsigned char *to = (unsigned char *)result.data();
- int ret = RSA_private_decrypt(flen, from, to, sec, oaep ? RSA_PKCS1_OAEP_PADDING : RSA_PKCS1_PADDING);
- if(ret == -1)
- return false;
- result.resize(ret);
-
- *out = result;
- return true;
- }
-
- RSA *pub, *sec;
-};
-
-static TQValueList<TQCA_CertProperty> nameToProperties(struct X509_name_st *name)
-{
- TQValueList<TQCA_CertProperty> list;
-
- for(int n = 0; n < X509_NAME_entry_count(name); ++n) {
- X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, n);
- TQCA_CertProperty p;
-
- ASN1_OBJECT *ao = X509_NAME_ENTRY_get_object(ne);
- int nid = OBJ_obj2nid(ao);
- if(nid == NID_undef)
- continue;
- p.var = OBJ_nid2sn(nid);
-
- ASN1_STRING *as = X509_NAME_ENTRY_get_data(ne);
- TQCString c;
- c.resize(as->length+1);
- strncpy(c.data(), (char *)as->data, as->length);
- p.val = TQString::fromLatin1(c);
- list += p;
- }
-
- return list;
-}
-
-// (taken from tdelibs) -- Justin
-//
-// This code is mostly taken from OpenSSL v0.9.5a
-// by Eric Young
-TQDateTime ASN1_UTCTIME_TQDateTime(ASN1_UTCTIME *tm, int *isGmt)
-{
- TQDateTime qdt;
- char *v;
- int gmt=0;
- int i;
- int y=0,M=0,d=0,h=0,m=0,s=0;
- TQDate qdate;
- TQTime qtime;
-
- i = tm->length;
- v = (char *)tm->data;
-
- if (i < 10) goto auq_err;
- if (v[i-1] == 'Z') gmt=1;
- for (i=0; i<10; i++)
- if ((v[i] > '9') || (v[i] < '0')) goto auq_err;
- y = (v[0]-'0')*10+(v[1]-'0');
- if (y < 50) y+=100;
- M = (v[2]-'0')*10+(v[3]-'0');
- if ((M > 12) || (M < 1)) goto auq_err;
- d = (v[4]-'0')*10+(v[5]-'0');
- h = (v[6]-'0')*10+(v[7]-'0');
- m = (v[8]-'0')*10+(v[9]-'0');
- if ( (v[10] >= '0') && (v[10] <= '9') &&
- (v[11] >= '0') && (v[11] <= '9'))
- s = (v[10]-'0')*10+(v[11]-'0');
-
- // localize the date and display it.
- qdate.setYMD(y+1900, M, d);
- qtime.setHMS(h,m,s);
- qdt.setDate(qdate); qdt.setTime(qtime);
-auq_err:
- if (isGmt) *isGmt = gmt;
- return qdt;
-}
-
-// (adapted from tdelibs) -- Justin
-static bool cnMatchesAddress(const TQString &_cn, const TQString &peerHost)
-{
- TQString cn = _cn.stripWhiteSpace().lower();
- TQRegExp rx;
-
- // Check for invalid characters
- if(TQRegExp("[^a-zA-Z0-9\\.\\*\\-]").search(cn) >= 0)
- return false;
-
- // Domains can legally end with '.'s. We don't need them though.
- while(cn.endsWith("."))
- cn.truncate(cn.length()-1);
-
- // Do not let empty CN's get by!!
- if(cn.isEmpty())
- return false;
-
- // Check for IPv4 address
- rx.setPattern("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
- if(rx.exactMatch(peerHost))
- return peerHost == cn;
-
- // Check for IPv6 address here...
- rx.setPattern("^\\[.*\\]$");
- if(rx.exactMatch(peerHost))
- return peerHost == cn;
-
- if(cn.contains('*')) {
- // First make sure that there are at least two valid parts
- // after the wildcard (*).
- TQStringList parts = TQStringList::split('.', cn, false);
-
- while(parts.count() > 2)
- parts.remove(parts.begin());
-
- if(parts.count() != 2) {
- return false; // we don't allow *.root - that's bad
- }
-
- if(parts[0].contains('*') || parts[1].contains('*')) {
- return false;
- }
-
- // RFC2818 says that *.example.com should match against
- // foo.example.com but not bar.foo.example.com
- // (ie. they must have the same number of parts)
- if(TQRegExp(cn, false, true).exactMatch(peerHost) &&
- TQStringList::split('.', cn, false).count() ==
- TQStringList::split('.', peerHost, false).count())
- return true;
-
- return false;
- }
-
- // We must have an exact match in this case (insensitive though)
- // (note we already did .lower())
- if(cn == peerHost)
- return true;
- return false;
-}
-
-class CertContext : public TQCA_CertContext
-{
-public:
- CertContext()
- {
- x = 0;
- }
-
- ~CertContext()
- {
- reset();
- }
-
- TQCA_CertContext *clone() const
- {
- CertContext *c = new CertContext(*this);
- if(x) {
- c->x = X509_dup(x);
- }
- return c;
- }
-
- void reset()
- {
- if(x) {
- X509_free(x);
- x = 0;
-
- serial = "";
- v_subject = "";
- v_issuer = "";
- cp_subject.clear();
- cp_issuer.clear();
- na = TQDateTime();
- nb = TQDateTime();
- }
- }
-
- bool isNull() const
- {
- return (x ? false: true);
- }
-
- bool createFromDER(const char *in, unsigned int len)
- {
- const unsigned char *p = (const unsigned char *)in;
- X509 *t = d2i_X509(NULL, &p, len);
- if(!t)
- return false;
- fromX509(t);
- X509_free(t);
- return true;
- }
-
- bool createFromPEM(const char *in, unsigned int len)
- {
- BIO *bi = BIO_new(BIO_s_mem());
- BIO_write(bi, in, len);
- X509 *t = PEM_read_bio_X509(bi, NULL, NULL, NULL);
- BIO_free(bi);
- if(!t)
- return false;
- fromX509(t);
- X509_free(t);
- return true;
- }
-
- bool toDER(TQByteArray *out)
- {
- int len = i2d_X509(x, NULL);
- TQByteArray buf(len);
- unsigned char *p = (unsigned char *)buf.data();
- i2d_X509(x, &p);
- *out = buf;
- return true;
- }
-
- bool toPEM(TQByteArray *out)
- {
- BIO *bo = BIO_new(BIO_s_mem());
- PEM_write_bio_X509(bo, x);
- *out = bio2buf(bo);
- return true;
- }
-
- void fromX509(X509 *t)
- {
- reset();
- x = X509_dup(t);
-
- // serial number
- ASN1_INTEGER *ai = X509_get_serialNumber(x);
- if(ai) {
- char *rep = i2s_ASN1_INTEGER(NULL, ai);
- serial = rep;
- OPENSSL_free(rep);
- }
-
- // validity dates
- nb = ASN1_UTCTIME_TQDateTime(X509_get_notBefore(x), NULL);
- na = ASN1_UTCTIME_TQDateTime(X509_get_notAfter(x), NULL);
-
- // extract the subject/issuer strings
- struct X509_name_st *sn = X509_get_subject_name(x);
- struct X509_name_st *in = X509_get_issuer_name(x);
- char buf[1024];
- X509_NAME_oneline(sn, buf, 1024);
- v_subject = buf;
- X509_NAME_oneline(in, buf, 1024);
- v_issuer = buf;
-
- // extract the subject/issuer contents
- cp_subject = nameToProperties(sn);
- cp_issuer = nameToProperties(in);
- }
-
- TQString serialNumber() const
- {
- return serial;
- }
-
- TQString subjectString() const
- {
- return v_subject;
- }
-
- TQString issuerString() const
- {
- return v_issuer;
- }
-
- TQValueList<TQCA_CertProperty> subject() const
- {
- return cp_subject;
- }
-
- TQValueList<TQCA_CertProperty> issuer() const
- {
- return cp_issuer;
- }
-
- TQDateTime notBefore() const
- {
- return nb;
- }
-
- TQDateTime notAfter() const
- {
- return na;
- }
-
- bool matchesAddress(const TQString &realHost) const
- {
- TQString peerHost = realHost.stripWhiteSpace();
- while(peerHost.endsWith("."))
- peerHost.truncate(peerHost.length()-1);
- peerHost = peerHost.lower();
-
- TQString cn;
- for(TQValueList<TQCA_CertProperty>::ConstIterator it = cp_subject.begin(); it != cp_subject.end(); ++it) {
- if((*it).var == "CN") {
- cn = (*it).val;
- break;
- }
- }
- if(cnMatchesAddress(cn, peerHost))
- return true;
- return false;
- }
-
- X509 *x;
- TQString serial, v_subject, v_issuer;
- TQValueList<TQCA_CertProperty> cp_subject, cp_issuer;
- TQDateTime nb, na;
-};
-
-static bool ssl_init = false;
-class TLSContext : public TQCA_TLSContext
-{
-public:
- enum { Good, TryAgain, Bad };
- enum { Idle, Connect, Accept, Handshake, Active, Closing };
-
- bool serv;
- int mode;
- TQByteArray sendQueue, recvQueue;
-
- CertContext *cert;
- RSAKeyContext *key;
-
- SSL *ssl;
- SSL_METHOD *method;
- SSL_CTX *context;
- BIO *rbio, *wbio;
- CertContext cc;
- int vr;
- bool v_eof;
-
- TLSContext()
- {
- if(!ssl_init) {
- SSL_library_init();
- SSL_load_error_strings();
- ssl_init = true;
- }
-
- ssl = 0;
- context = 0;
- cert = 0;
- key = 0;
- }
-
- ~TLSContext()
- {
- reset();
- }
-
- void reset()
- {
- if(ssl) {
- SSL_free(ssl);
- ssl = 0;
- }
- if(context) {
- SSL_CTX_free(context);
- context = 0;
- }
- if(cert) {
- delete cert;
- cert = 0;
- }
- if(key) {
- delete key;
- key = 0;
- }
-
- sendQueue.resize(0);
- recvQueue.resize(0);
- mode = Idle;
- cc.reset();
- vr = TQCA::TLS::Unknown;
- v_eof = false;
- }
-
- bool eof() const
- {
- return v_eof;
- }
-
- bool startClient(const TQPtrList<TQCA_CertContext> &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key)
- {
- reset();
- serv = false;
- method = const_cast<SSL_METHOD*>(SSLv23_client_method());
-
- if(!setup(store, _cert, _key))
- return false;
-
- mode = Connect;
- return true;
- }
-
- bool startServer(const TQPtrList<TQCA_CertContext> &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key)
- {
- reset();
- serv = true;
- method = const_cast<SSL_METHOD*>(SSLv23_server_method());
-
- if(!setup(store, _cert, _key))
- return false;
-
- mode = Accept;
- return true;
- }
-
- bool setup(const TQPtrList<TQCA_CertContext> &list, const TQCA_CertContext &_cc, const TQCA_RSAKeyContext &kc)
- {
- context = SSL_CTX_new(method);
- if(!context) {
- reset();
- return false;
- }
-
- // load the cert store
- if(!list.isEmpty()) {
- X509_STORE *store = SSL_CTX_get_cert_store(context);
- TQPtrListIterator<TQCA_CertContext> it(list);
- for(CertContext *i; (i = (CertContext *)it.current()); ++it)
- X509_STORE_add_cert(store, i->x);
- }
-
- ssl = SSL_new(context);
- if(!ssl) {
- reset();
- return false;
- }
- SSL_set_ssl_method(ssl, method); // can this return error?
-
- // setup the memory bio
- rbio = BIO_new(BIO_s_mem());
- wbio = BIO_new(BIO_s_mem());
-
- // 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 handshake(const TQByteArray &in, TQByteArray *out)
- {
- if(!in.isEmpty())
- BIO_write(rbio, in.data(), in.size());
-
- if(mode == Connect) {
- int ret = doConnect();
- if(ret == Good) {
- mode = Handshake;
- }
- else if(ret == Bad) {
- reset();
- return Error;
- }
- }
-
- if(mode == Accept) {
- int ret = doAccept();
- if(ret == Good) {
- getCert();
- mode = Active;
- }
- else if(ret == Bad) {
- reset();
- return Error;
- }
- }
-
- if(mode == Handshake) {
- int ret = doHandshake();
- if(ret == Good) {
- getCert();
- mode = Active;
- }
- else if(ret == Bad) {
- reset();
- return Error;
- }
- }
-
- // process outgoing
- *out = readOutgoing();
-
- if(mode == Active)
- return Success;
- else
- return Continue;
- }
-
- int shutdown(const TQByteArray &in, TQByteArray *out)
- {
- if(!in.isEmpty())
- BIO_write(rbio, in.data(), in.size());
-
- int ret = doShutdown();
- if(ret == Bad) {
- reset();
- return Error;
- }
-
- *out = readOutgoing();
-
- if(ret == Good) {
- mode = Idle;
- return Success;
- }
- else {
- mode = Closing;
- return Continue;
- }
- }
-
- void getCert()
- {
- // verify the certificate
- int code = TQCA::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 = TQCA::TLS::Valid;
- else
- code = resultToCV(ret);
- }
- else {
- cc.reset();
- code = TQCA::TLS::NoCert;
- }
- vr = code;
- }
-
- bool encode(const TQByteArray &plain, TQByteArray *to_net, int *enc)
- {
- if(mode != Active)
- return false;
- appendArray(&sendQueue, plain);
-
- int encoded = 0;
- if(sendQueue.size() > 0) {
- int ret = SSL_write(ssl, sendQueue.data(), sendQueue.size());
-
- enum { Good, Continue, Done, Error };
- int m;
- if(ret <= 0) {
- int x = SSL_get_error(ssl, ret);
- if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
- m = Continue;
- else if(x == SSL_ERROR_ZERO_RETURN)
- m = Done;
- else
- m = Error;
- }
- else {
- m = Good;
- encoded = ret;
- int newsize = sendQueue.size() - encoded;
- char *r = sendQueue.data();
- memmove(r, r + encoded, newsize);
- sendQueue.resize(newsize);
- }
-
- if(m == Done) {
- sendQueue.resize(0);
- v_eof = true;
- return false;
- }
- if(m == Error) {
- sendQueue.resize(0);
- return false;
- }
- }
-
- *to_net = readOutgoing();
- *enc = encoded;
- return true;
- }
-
- bool decode(const TQByteArray &from_net, TQByteArray *plain, TQByteArray *to_net)
- {
- if(mode != Active)
- return false;
- if(!from_net.isEmpty())
- BIO_write(rbio, from_net.data(), from_net.size());
-
- TQByteArray a;
- while(!v_eof) {
- a.resize(8192);
- int ret = SSL_read(ssl, a.data(), a.size());
- if(ret > 0) {
- if(ret != (int)a.size())
- a.resize(ret);
- appendArray(&recvQueue, a);
- }
- else if(ret <= 0) {
- int x = SSL_get_error(ssl, ret);
- if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
- break;
- else if(x == SSL_ERROR_ZERO_RETURN)
- v_eof = true;
- else
- return false;
- }
- }
-
- *plain = recvQueue.copy();
- recvQueue.resize(0);
-
- // could be outgoing data also
- *to_net = readOutgoing();
- return true;
- }
-
- TQByteArray unprocessed()
- {
- TQByteArray a;
- int size = BIO_pending(rbio);
- if(size <= 0)
- return a;
- a.resize(size);
-
- int r = BIO_read(rbio, a.data(), size);
- if(r <= 0) {
- a.resize(0);
- return a;
- }
- if(r != size)
- a.resize(r);
- return a;
- }
-
- TQByteArray readOutgoing()
- {
- TQByteArray a;
- int size = BIO_pending(wbio);
- if(size <= 0)
- return a;
- a.resize(size);
-
- int r = BIO_read(wbio, a.data(), size);
- if(r <= 0) {
- a.resize(0);
- return a;
- }
- if(r != size)
- a.resize(r);
- return a;
- }
-
- int doConnect()
- {
- 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;
- }
-
- 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
- return Bad;
- }
- else if(ret == 0)
- return Bad;
- return Good;
- }
-
- 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 Bad;
- }
- else if(ret == 0)
- return Bad;
- return Good;
- }
-
- int doShutdown()
- {
- int ret = SSL_shutdown(ssl);
- if(ret >= 1)
- return Good;
- else {
- if(ret == 0)
- return TryAgain;
- int x = SSL_get_error(ssl, ret);
- if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE)
- return TryAgain;
- return Bad;
- }
- }
-
- TQCA_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 = TQCA::TLS::Rejected;
- break;
- case X509_V_ERR_CERT_UNTRUSTED:
- rc = TQCA::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 = TQCA::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 = TQCA::TLS::InvalidCA;
- break;
- case X509_V_ERR_INVALID_PURPOSE:
- rc = TQCA::TLS::InvalidPurpose;
- break;
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- rc = TQCA::TLS::SelfSigned;
- break;
- case X509_V_ERR_CERT_REVOKED:
- rc = TQCA::TLS::Revoked;
- break;
- case X509_V_ERR_PATH_LENGTH_EXCEEDED:
- rc = TQCA::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 = TQCA::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 = TQCA::TLS::Unknown;
- break;
- }
- return rc;
- }
-};
-
-class TQCAOpenSSL : public TQCAProvider
-{
-public:
- TQCAOpenSSL() {}
- ~TQCAOpenSSL() {}
-
- void init()
- {
- }
-
- int qcaVersion() const
- {
- return TQCA_PLUGIN_VERSION;
- }
-
- int capabilities() const
- {
- int caps =
- TQCA::CAP_SHA1 |
- TQCA::CAP_MD5 |
- TQCA::CAP_BlowFish |
- TQCA::CAP_TripleDES |
-#ifndef NO_AES
- TQCA::CAP_AES128 |
- TQCA::CAP_AES256 |
-#endif
- TQCA::CAP_RSA |
- TQCA::CAP_X509 |
- TQCA::CAP_TLS;
- return caps;
- }
-
- void *context(int cap)
- {
- if(cap == TQCA::CAP_SHA1)
- return new SHA1Context;
- else if(cap == TQCA::CAP_MD5)
- return new MD5Context;
- else if(cap == TQCA::CAP_BlowFish)
- return new BlowFishContext;
- else if(cap == TQCA::CAP_TripleDES)
- return new TripleDESContext;
-#ifndef NO_AES
- else if(cap == TQCA::CAP_AES128)
- return new AES128Context;
- else if(cap == TQCA::CAP_AES256)
- return new AES256Context;
-#endif
- else if(cap == TQCA::CAP_RSA)
- return new RSAKeyContext;
- else if(cap == TQCA::CAP_X509)
- return new CertContext;
- else if(cap == TQCA::CAP_TLS)
- return new TLSContext;
- return 0;
- }
-};
-
-#ifdef TQCA_PLUGIN
-TQCAProvider *createProvider()
-#else
-TQCAProvider *createProviderTLS()
-#endif
-{
- return (new TQCAOpenSSL);
-}