diff --git a/CMakeLists.txt b/CMakeLists.txt index c3fe32e..906c1ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,9 +25,9 @@ if (ANDROID) endif() if (NOT QT_VERSION_MAJOR) - find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test REQUIRED) + find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Network Test REQUIRED) endif() -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network Test REQUIRED) include(submodules/CMake/QuasarApp.cmake) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 9aca4a0..a4911da 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -33,7 +33,7 @@ set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/private") add_library(${CURRENT_PROJECT} ${SOURCE_CPP} ${SOURCE_QRC}) -target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt${QT_VERSION_MAJOR}::Core ) +target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Core ) if (EASYSSL_STATIC_SSL) diff --git a/src/lib/src/private/easysslutils.cpp b/src/lib/src/private/easysslutils.cpp index 85bf5db..31f6b89 100644 --- a/src/lib/src/private/easysslutils.cpp +++ b/src/lib/src/private/easysslutils.cpp @@ -8,6 +8,7 @@ #include "easysslutils.h" #include #include +#include #include #include @@ -57,4 +58,36 @@ BIO* EasySSLUtils::byteArrayToBio(const QByteArray& byteArray) { return bio; } +QByteArray EasySSLUtils::extractPublcKey(EVP_PKEY *ssl_keys) { + if (!ssl_keys) + return {}; + + BIO* bio = BIO_new(BIO_s_mem()); + if (PEM_write_bio_PUBKEY(bio, ssl_keys) != 1) { + BIO_free(bio); + return {}; + } + + QByteArray pubKey = bioToByteArray(bio); + BIO_free(bio); + + return pubKey; +} + +QByteArray EasySSLUtils::extractPrivateKey(EVP_PKEY *ssl_keys) { + if (!ssl_keys) + return {}; + + BIO* bio = BIO_new(BIO_s_mem()); + if (PEM_write_bio_PrivateKey(bio, ssl_keys, nullptr, nullptr, 0, nullptr, nullptr) != 1) { + BIO_free(bio); + return {}; + } + + QByteArray pKey = bioToByteArray(bio); + BIO_free(bio); + + return pKey; +} + } diff --git a/src/lib/src/private/easysslutils.h b/src/lib/src/private/easysslutils.h index 651099f..aea9adc 100644 --- a/src/lib/src/private/easysslutils.h +++ b/src/lib/src/private/easysslutils.h @@ -53,6 +53,21 @@ public: */ [[nodiscard("This pointer will not free automatically. Please free returned pointer after using.")]] static BIO *byteArrayToBio(const QByteArray &byteArray); + + /** + * @brief extractPublcKey This method extracts publick key from the ssl (pem) structure. + * @param ssl_keys This is ssl keys objects. + * @return bytes array of the extracted key. + */ + static QByteArray extractPublcKey(EVP_PKEY* ssl_keys); + + /** + * @brief extractPrivateKey This method extracts private key from the ssl (pem) structure. + * @param ssl_keys This is ssl keys objects. + * @return bytes array of the extracted key. + */ + static QByteArray extractPrivateKey(EVP_PKEY* ssl_keys); + }; diff --git a/src/lib/src/public/easyssl/icertificate.cpp b/src/lib/src/public/easyssl/icertificate.cpp new file mode 100644 index 0000000..ec10073 --- /dev/null +++ b/src/lib/src/public/easyssl/icertificate.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021-2023 QuasarApp. + * Distributed under the GPLv3 software license, see the accompanying + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. +*/ + + + +#include "icertificate.h" + + +namespace EasySSL { + +ICertificate::ICertificate(const QSharedPointer &generator) { + _keyGenerator = generator; +} + +const QSharedPointer &ICertificate::keyGenerator() const { + return _keyGenerator; +} + +} diff --git a/src/lib/src/public/easyssl/icertificate.h b/src/lib/src/public/easyssl/icertificate.h new file mode 100644 index 0000000..f8c663a --- /dev/null +++ b/src/lib/src/public/easyssl/icertificate.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021-2023 QuasarApp. + * Distributed under the GPLv3 software license, see the accompanying + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. +*/ + +#ifndef ICERTIFICATE_H +#define ICERTIFICATE_H + +#include +#include +#include "easyssl/icrypto.h" +#include "global.h" +#include + +namespace EasySSL { + +/** + * @brief The SslSrtData struct This structure contains base information for generate self signed ssl certefication. + */ +struct SslSrtData { + QString country = "BY"; + QString organization = "QuasarApp"; + QString commonName = ""; + long long endTime = 31536000L; //1 year +}; + +/** + * @brief The SelfSignedSertificate struct contains qt certificate object and private key of them. + */ +struct EASYSSL_EXPORT SelfSignedSertificate { + SelfSignedSertificate(){} + SelfSignedSertificate(const SelfSignedSertificate & other) { + crt = other.crt; + key = other.key; + }; + QSslCertificate crt; + QSslKey key; +}; + +/** + * @brief The ICertificate class is base interface for all certificate generators classes. + * + */ +class EASYSSL_EXPORT ICertificate +{ +public: + + ICertificate(const QSharedPointer& generator); + + /** + * @brief create This method create a self signed certificate. + * @param certificateData This input extra data of certificate. + * @return certificate data with private key. + */ + virtual SelfSignedSertificate create(const SslSrtData& certificateData) const = 0; + +protected: + /** + * @brief generator This method return private key generator. + * @return private key generator. + */ + const QSharedPointer& keyGenerator() const; + +private: + QSharedPointer _keyGenerator; +}; + +} +#endif // ICERTIFICATE_H diff --git a/src/lib/src/public/easyssl/icrypto.cpp b/src/lib/src/public/easyssl/icrypto.cpp new file mode 100644 index 0000000..9ce0f49 --- /dev/null +++ b/src/lib/src/public/easyssl/icrypto.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021-2023 QuasarApp. + * Distributed under the GPLv3 software license, see the accompanying + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. +*/ + +#include "icrypto.h" + +#include +#include +#include + +namespace EasySSL { + +bool EasySSL::ICrypto::makeKeys(QByteArray &pubKey, QByteArray &privKey) const +{ + EVP_PKEY *keys = makeRawKeys(); + if (!keys) + return false; + + pubKey = EasySSLUtils::extractPublcKey(keys); + privKey = EasySSLUtils::extractPrivateKey(keys); + return true; +} + + +} diff --git a/src/lib/src/public/easyssl/icrypto.h b/src/lib/src/public/easyssl/icrypto.h index 4a5938b..42c7a68 100644 --- a/src/lib/src/public/easyssl/icrypto.h +++ b/src/lib/src/public/easyssl/icrypto.h @@ -10,7 +10,9 @@ #define I_CRYPTO_H #include "global.h" +#include "qssl.h" #include +#include namespace EasySSL { @@ -38,7 +40,19 @@ public: * @param privKey This is result private key. * @return true if keys generated successful. */ - virtual bool makeKeys(QByteArray &pubKey, QByteArray &privKey) const = 0; + bool makeKeys(QByteArray &pubKey, QByteArray &privKey) const; + + /** + * @brief makeKeys This method generate the public and private keys of the ECDSA. + * @return pointer to generated keys. + */ + virtual EVP_PKEY * makeRawKeys() const = 0; + + /** + * @brief keyAlgorithm This method should be return Qt Key algorithm (needed for generate cetrificates.) + * @return + */ + virtual QSsl::KeyAlgorithm keyAlgorithm() const = 0; /** * @brief supportedFeatures This method should return supported featurs of the current encription alhorithm diff --git a/src/lib/src/public/easyssl/rsassl30.cpp b/src/lib/src/public/easyssl/rsassl30.cpp index 56148ed..01b4fed 100644 --- a/src/lib/src/public/easyssl/rsassl30.cpp +++ b/src/lib/src/public/easyssl/rsassl30.cpp @@ -20,37 +20,17 @@ RSASSL30::RSASSL30() { } -bool RSASSL30::makeKeys(QByteArray &pubKey, QByteArray &privKey) const { +EVP_PKEY * RSASSL30::makeRawKeys() const { EVP_PKEY *pkey = nullptr; - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr); EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 4096); EVP_PKEY_keygen_init(pctx); EVP_PKEY_generate(pctx, &pkey); EVP_PKEY_CTX_free(pctx); - if (!pkey) { - return false; - } - - BIO* bio = BIO_new(BIO_s_mem()); - if (PEM_write_bio_PUBKEY(bio, pkey) != 1) { - EVP_PKEY_free(pkey); - return false; - } - pubKey = EasySSLUtils::bioToByteArray(bio); - - if (PEM_write_bio_PrivateKey(bio, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1) - { - EVP_PKEY_free(pkey); - return false; - } - - privKey = EasySSLUtils::bioToByteArray(bio); - - return true; - + return pkey; } ICrypto::Features RSASSL30::supportedFeatures() const { diff --git a/src/lib/src/public/easyssl/rsassl30.h b/src/lib/src/public/easyssl/rsassl30.h index 25ecab0..951f2a1 100644 --- a/src/lib/src/public/easyssl/rsassl30.h +++ b/src/lib/src/public/easyssl/rsassl30.h @@ -1,3 +1,11 @@ +//# +//# Copyright (C) 2021-2023 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + + #ifndef RSASSL30_H #define RSASSL30_H @@ -14,10 +22,9 @@ class EASYSSL_EXPORT RSASSL30: public EasySSL::ICrypto public: RSASSL30(); - bool makeKeys(QByteArray &pubKey, QByteArray &privKey) const override; + EVP_PKEY *makeRawKeys() const override; Features supportedFeatures() const override; - QByteArray signMessage(const QByteArray &inputData, const QByteArray &key) const override; bool checkSign(const QByteArray &inputData, const QByteArray &signature, const QByteArray &key) const override; diff --git a/src/lib/src/public/easyssl/x509.cpp b/src/lib/src/public/easyssl/x509.cpp index a184a17..fb2db39 100644 --- a/src/lib/src/public/easyssl/x509.cpp +++ b/src/lib/src/public/easyssl/x509.cpp @@ -1,6 +1,86 @@ -#include "x509.h" +//# +//# Copyright (C) 2021-2023 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# -X509::X509() -{ +#include "x509.h" +#include +#include +#include +#include +namespace EasySSL { + +X509::X509(const QSharedPointer& generator): ICertificate(generator) { + +} + +SelfSignedSertificate X509::create(const SslSrtData &certificateData) const { + SelfSignedSertificate result; + if (!(keyGenerator()->supportedFeatures() & ICrypto::Features::Signing)) { + return {}; + } + + EVP_PKEY *pkey = keyGenerator()->makeRawKeys(); + + ::X509 * x509 = nullptr; + X509_NAME * name = nullptr; + + x509 = X509_new(); + q_check_ptr(x509); + ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); + X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time + X509_gmtime_adj(X509_get_notAfter(x509), certificateData.endTime); // not after a year from this point + X509_set_pubkey(x509, pkey); + name = X509_get_subject_name(x509); + q_check_ptr(name); + + unsigned char *C = reinterpret_cast(certificateData.country.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, C, -1, -1, 0); + + unsigned char *O = reinterpret_cast(certificateData.organization.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, O, -1, -1, 0); + + unsigned char *CN = reinterpret_cast(certificateData.commonName.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, CN, -1, -1, 0); + + X509_set_issuer_name(x509, name); + X509_sign(x509, pkey, EVP_sha256()); + + result.key = QSslKey(EasySSLUtils::extractPrivateKey(pkey), keyGenerator()->keyAlgorithm()); + if(result.key.isNull()) { + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + qCritical("Failed to generate a random private key"); + return {}; + } + EVP_PKEY_free(pkey); + BIO_free_all(bp_private); + + BIO * bp_public = BIO_new(BIO_s_mem()); + q_check_ptr(bp_public); + if(PEM_write_bio_X509(bp_public, x509) != 1){ + X509_free(x509); + BIO_free_all(bp_public); + qCritical("PEM_write_bio_PrivateKey"); + return {}; + } + + result.crt = QSslCertificate(EasySSLUtils::bioToByteArray(bp_public)); + if(result.crt.isNull()) { + X509_free(x509); + BIO_free_all(bp_public); + qCritical("Failed to generate a random client certificate"); + return {}; + } + + X509_free(x509); + BIO_free_all(bp_public); + + return result; +} } diff --git a/src/lib/src/public/easyssl/x509.h b/src/lib/src/public/easyssl/x509.h index 11fad76..737df3c 100644 --- a/src/lib/src/public/easyssl/x509.h +++ b/src/lib/src/public/easyssl/x509.h @@ -1,11 +1,31 @@ +//# +//# Copyright (C) 2021-2023 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + #ifndef X509_H #define X509_H +#include "global.h" +#include "icertificate.h" +#include "icrypto.h" -class X509 +namespace EasySSL { + +/** + * @brief The X509 class This is wrapper of the ssl objects. + */ +class EASYSSL_EXPORT X509: public ICertificate { public: - X509(); + X509(const QSharedPointer& generator); + + // ICertificate interface +public: + SelfSignedSertificate create(const SslSrtData& certificateData) const override; }; +} #endif // X509_H