diff options
author | gregory guy <gregory-tde@laposte.net> | 2020-01-02 15:12:40 +0100 |
---|---|---|
committer | Slávek Banko <slavek.banko@axis.cz> | 2020-01-22 16:16:32 +0100 |
commit | a2c0e6c98197215ac788982fbf5b236888eef79e (patch) | |
tree | 7ea36879375d9ad579fcdf226a605a36232e827b /qca-tls.cpp | |
parent | 9cd1493c36e94b9bfd36e35bc197ecf87634970e (diff) | |
download | tqca-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.cpp | 1510 |
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); -} |