added support x509 certificates for qt

This commit is contained in:
Andrei Yankovich 2023-07-08 11:58:18 +02:00
parent fcbf421535
commit a84929b069
12 changed files with 305 additions and 34 deletions

View File

@ -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)

View File

@ -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)

View File

@ -8,6 +8,7 @@
#include "easysslutils.h"
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/types.h>
#include <QVector>
@ -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;
}
}

View File

@ -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);
};

View File

@ -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<ICrypto> &generator) {
_keyGenerator = generator;
}
const QSharedPointer<ICrypto> &ICertificate::keyGenerator() const {
return _keyGenerator;
}
}

View File

@ -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 <QSslCertificate>
#include <QSslKey>
#include "easyssl/icrypto.h"
#include "global.h"
#include <QByteArray>
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<ICrypto>& 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<ICrypto>& keyGenerator() const;
private:
QSharedPointer<ICrypto> _keyGenerator;
};
}
#endif // ICERTIFICATE_H

View File

@ -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 <easysslutils.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
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;
}
}

View File

@ -10,7 +10,9 @@
#define I_CRYPTO_H
#include "global.h"
#include "qssl.h"
#include <QByteArray>
#include <openssl/types.h>
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

View File

@ -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 {

View File

@ -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;

View File

@ -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 <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <easysslutils.h>
namespace EasySSL {
X509::X509(const QSharedPointer<ICrypto>& 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<unsigned char *>(certificateData.country.toLatin1().data());
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, C, -1, -1, 0);
unsigned char *O = reinterpret_cast<unsigned char *>(certificateData.organization.toLatin1().data());
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, O, -1, -1, 0);
unsigned char *CN = reinterpret_cast<unsigned char *>(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;
}
}

View File

@ -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<ICrypto>& generator);
// ICertificate interface
public:
SelfSignedSertificate create(const SslSrtData& certificateData) const override;
};
}
#endif // X509_H