From a2c0e6c98197215ac788982fbf5b236888eef79e Mon Sep 17 00:00:00 2001 From: gregory guy Date: Thu, 2 Jan 2020 15:12:40 +0100 Subject: Conversion to the cmake building system. Signed-off-by: gregory guy --- CMakeLists.txt | 96 ++++ ConfigureChecks.cmake | 56 ++ config.h.cmake | 11 + qca-tls.cpp | 1510 ------------------------------------------------- qca-tls.h | 32 -- qcaprovider.h | 11 +- tqca-tls.cpp | 1510 +++++++++++++++++++++++++++++++++++++++++++++++++ tqca-tls.h | 39 ++ 8 files changed, 1722 insertions(+), 1543 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 ConfigureChecks.cmake create mode 100644 config.h.cmake delete mode 100644 qca-tls.cpp delete mode 100644 qca-tls.h create mode 100644 tqca-tls.cpp create mode 100644 tqca-tls.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f41a4b5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,96 @@ +############################################ +# # +# Improvements and feedbacks are welcome # +# # +# This file is released under GPL >= 3 # +# # +############################################ + + +cmake_minimum_required( VERSION 2.8 ) + + +#### general package setup + +project( tqca-tls ) +set( VERSION R14.1.0 ) + + +#### include essential cmake modules + +include( FindPkgConfig ) +include( CheckFunctionExists ) +include( CheckSymbolExists ) +include( CheckIncludeFile ) +include( CheckLibraryExists ) +include( CheckCSourceCompiles ) +include( CheckCXXSourceCompiles ) + + +#### include our cmake modules + +set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" ) +include( TDEMacros ) + + +##### setup install paths + +include( TDESetupPaths ) +tde_setup_paths( ) + + +##### optional stuff + +option( WITH_ALL_OPTIONS "Enable all optional support" OFF ) +option( WITH_GCC_VISIBILITY "Enable fvisibility and fvisibility-inlines-hidden" ${WITH_ALL_OPTIONS} ) + + +##### configure checks + +include( ConfigureChecks.cmake ) + + +###### global compiler settings + +add_definitions( -DHAVE_CONFIG_H -DOSSL_097 -DTQCA_PLUGIN ) + +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TQT_CXX_FLAGS}" ) +set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) +set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined" ) + + +##### write configure files + +configure_file( config.h.cmake config.h @ONLY ) + + +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${TQT_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIR} +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### tqca-tls (shared) + +tde_add_library( ${PROJECT_NAME} SHARED NO_LIBTOOL_FILE AUTOMOC + + SOURCES + tqca-tls.cpp + LINK + ${TQT_LIBRARIES} + ${OPENSSL_LIBRARIES} + + DESTINATION ${TQT_PLUGINS_CRYPTO_DIR} +) + + +##### write configure files + +configure_file( config.h.cmake config.h @ONLY ) diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake new file mode 100644 index 0000000..22cea81 --- /dev/null +++ b/ConfigureChecks.cmake @@ -0,0 +1,56 @@ +########################################### +# # +# Improvements and feedback are welcome # +# # +# This file is released under GPL >= 3 # +# # +########################################### + +# required stuff +find_package( TQt ) + +tde_setup_architecture_flags( ) + +include(TestBigEndian) +test_big_endian(WORDS_BIGENDIAN) + +tde_setup_largefiles( ) + + +##### check for gcc visibility support + +if( WITH_GCC_VISIBILITY ) + tde_setup_gcc_visibility( ) +endif( WITH_GCC_VISIBILITY ) + + +##### check for openssl + +find_package( OpenSSL ) +if( NOT OPENSSL_FOUND ) + tde_message_fatal( "OpenSSL is required but was not found on your system" ) +endif() + + +##### look for tqt3 plugins path + +execute_process( + COMMAND ${PKG_CONFIG_EXECUTABLE} + --variable=pluginsdir tqt-mt + OUTPUT_VARIABLE TQT_PLUGINS_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if( TQT_PLUGINS_DIR ) + set( TQT_PLUGINS_CRYPTO_DIR "${TQT_PLUGINS_DIR}/crypto" ) +endif() + + +###### check for tqca + +pkg_search_module( TQCA tqca ) + if( TQCA_FOUND ) + set( HAVE_TQCA 1 ) + else() + message( STATUS " tqca was not found, built-in copy will be used" ) + endif( ) + diff --git a/config.h.cmake b/config.h.cmake new file mode 100644 index 0000000..44441e0 --- /dev/null +++ b/config.h.cmake @@ -0,0 +1,11 @@ +#define VERSION "@VERSION@" + +// Defined if you have fvisibility and fvisibility-inlines-hidden support. +#cmakedefine __KDE_HAVE_GCC_VISIBILITY 1 + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#cmakedefine WORDS_BIGENDIAN @WORDS_BIGENDIAN@ + +/* Defined if you have the tqca library */ +#cmakedefine HAVE_TQCA 1 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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 nameToProperties(struct X509_name_st *name) -{ - TQValueList 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 subject() const - { - return cp_subject; - } - - TQValueList 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::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 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 &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key) - { - reset(); - serv = false; - method = const_cast(SSLv23_client_method()); - - if(!setup(store, _cert, _key)) - return false; - - mode = Connect; - return true; - } - - bool startServer(const TQPtrList &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key) - { - reset(); - serv = true; - method = const_cast(SSLv23_server_method()); - - if(!setup(store, _cert, _key)) - return false; - - mode = Accept; - return true; - } - - bool setup(const TQPtrList &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 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(_cc.clone()); - key = static_cast(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); -} diff --git a/qca-tls.h b/qca-tls.h deleted file mode 100644 index 1594492..0000000 --- a/qca-tls.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * qca-tls.h - 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 - * - */ - -#ifndef TQCA_TLS_H -#define TQCA_TLS_H - -#include"qcaprovider.h" - -#ifdef TQCA_PLUGIN -TQCA_PLUGIN_EXPORT TQCAProvider *createProvider(); -#else -TQCAProvider *createProviderTLS(); -#endif - -#endif diff --git a/qcaprovider.h b/qcaprovider.h index 46c06c5..baf0e29 100644 --- a/qcaprovider.h +++ b/qcaprovider.h @@ -26,7 +26,16 @@ #include #include #include -#include"qca.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_TQCA +#include +#else +#include "qca.h" +#endif #define TQCA_PLUGIN_VERSION 1 diff --git a/tqca-tls.cpp b/tqca-tls.cpp new file mode 100644 index 0000000..df9eff1 --- /dev/null +++ b/tqca-tls.cpp @@ -0,0 +1,1510 @@ +/* + * 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 "tqca-tls.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 nameToProperties(struct X509_name_st *name) +{ + TQValueList 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 subject() const + { + return cp_subject; + } + + TQValueList 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::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 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 &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key) + { + reset(); + serv = false; + method = const_cast(SSLv23_client_method()); + + if(!setup(store, _cert, _key)) + return false; + + mode = Connect; + return true; + } + + bool startServer(const TQPtrList &store, const TQCA_CertContext &_cert, const TQCA_RSAKeyContext &_key) + { + reset(); + serv = true; + method = const_cast(SSLv23_server_method()); + + if(!setup(store, _cert, _key)) + return false; + + mode = Accept; + return true; + } + + bool setup(const TQPtrList &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 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(_cc.clone()); + key = static_cast(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); +} diff --git a/tqca-tls.h b/tqca-tls.h new file mode 100644 index 0000000..ed62c99 --- /dev/null +++ b/tqca-tls.h @@ -0,0 +1,39 @@ +/* + * qca-tls.h - 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 + * + */ + +#ifndef TQCA_TLS_H +#define TQCA_TLS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_TQCA +#include +#else +#include "qcaprovider.h" +#endif + +#ifdef TQCA_PLUGIN +TQCA_PLUGIN_EXPORT TQCAProvider *createProvider(); +#else +TQCAProvider *createProviderTLS(); +#endif +#endif -- cgit v1.2.1