File indexing completed on 2024-04-28 04:57:03
0001 /** 0002 * SPDX-FileCopyrightText: 2023 Albert Vaca <albertvaka@gmail.com> 0003 * SPDX-FileCopyrightText: 2023 Edward Kigwana <ekigwana@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "sslhelper.h" 0009 #include "core_debug.h" 0010 0011 extern "C" { 0012 #include <openssl/bn.h> 0013 #include <openssl/err.h> 0014 #include <openssl/evp.h> 0015 #include <openssl/pem.h> 0016 #include <openssl/rsa.h> 0017 #include <openssl/x509.h> 0018 } 0019 0020 namespace SslHelper 0021 { 0022 QString getSslError() 0023 { 0024 char buf[256]; 0025 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); 0026 return QString::fromLatin1(buf); 0027 } 0028 0029 QSslKey generateRsaPrivateKey() 0030 { 0031 // Initialize context. 0032 auto pctxRaw = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr); 0033 auto pctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(pctxRaw, ::EVP_PKEY_CTX_free); 0034 if (!pctx) { 0035 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to allocate context " << getSslError(); 0036 return QSslKey(); 0037 } 0038 0039 if (EVP_PKEY_keygen_init(pctx.get()) <= 0) { 0040 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to initialize context " << getSslError(); 0041 return QSslKey(); 0042 } 0043 0044 // Set key bits. 0045 if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx.get(), 2048) <= 0) { 0046 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to set key bits " << getSslError(); 0047 return QSslKey(); 0048 } 0049 0050 // Generate private key. 0051 auto pkey = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>(EVP_PKEY_new(), ::EVP_PKEY_free); 0052 if (!pkey) { 0053 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to allocate private key " << getSslError(); 0054 return QSslKey(); 0055 } 0056 0057 auto pkey_raw = pkey.get(); 0058 if (EVP_PKEY_keygen(pctx.get(), &pkey_raw) <= 0) { 0059 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to generate private key " << getSslError(); 0060 return QSslKey(); 0061 } 0062 0063 // Convert private key format to PEM as required by QSslKey. 0064 auto bio = std::unique_ptr<BIO, decltype(&::BIO_free_all)>(BIO_new(BIO_s_mem()), ::BIO_free_all); 0065 if (!bio) { 0066 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed to allocate I/O abstraction " << getSslError(); 0067 return QSslKey(); 0068 } 0069 0070 if (!PEM_write_bio_PrivateKey(bio.get(), pkey_raw, nullptr, nullptr, 0, nullptr, nullptr)) { 0071 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed write PEM format private key to BIO " << getSslError(); 0072 return QSslKey(); 0073 } 0074 0075 BUF_MEM *mem = nullptr; 0076 if (!BIO_get_mem_ptr(bio.get(), &mem)) { 0077 qCWarning(KDECONNECT_CORE) << "Generate RSA Private Key failed get PEM format address " << getSslError(); 0078 return QSslKey(); 0079 } 0080 0081 return QSslKey(QByteArray(mem->data, mem->length), QSsl::KeyAlgorithm::Rsa); 0082 } 0083 0084 QSslCertificate generateSelfSignedCertificate(const QSslKey &qtPrivateKey, const QString &commonName) 0085 { 0086 // Create certificate. 0087 auto x509 = std::unique_ptr<X509, decltype(&::X509_free)>(X509_new(), ::X509_free); 0088 if (!x509) { 0089 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to allocate certifcate " << getSslError(); 0090 return QSslCertificate(); 0091 } 0092 0093 if (!X509_set_version(x509.get(), 2)) { 0094 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set version " << getSslError(); 0095 return QSslCertificate(); 0096 } 0097 0098 // Generate a random serial number for the certificate. 0099 auto sn = std::unique_ptr<BIGNUM, decltype(&::BN_free)>(BN_new(), ::BN_free); 0100 if (!sn) { 0101 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to allocate big number structure " << getSslError(); 0102 return QSslCertificate(); 0103 } 0104 0105 if (!BN_rand(sn.get(), 160, -1, 0)) { // as per rfc3280, serial numbers must be 20 bytes (160 bits) or less 0106 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to generate random number " << getSslError(); 0107 return QSslCertificate(); 0108 } 0109 0110 if (!BN_to_ASN1_INTEGER(sn.get(), X509_get_serialNumber(x509.get()))) { 0111 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to convert number structure to integer" << getSslError(); 0112 return QSslCertificate(); 0113 } 0114 0115 // Set the certificate subject and issuer (self-signed). 0116 auto name = X509_get_subject_name(x509.get()); 0117 QByteArray commonNameBytes = commonName.toLatin1(); 0118 const unsigned char *commonNameCStr = reinterpret_cast<const unsigned char *>(commonNameBytes.data()); 0119 if (!X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, commonNameCStr, -1, -1, 0)) { // Common Name 0120 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set common name to " << commonName << " " << getSslError(); 0121 return QSslCertificate(); 0122 } 0123 0124 const unsigned char *organizationCStr = reinterpret_cast<const unsigned char *>("KDE"); 0125 if (!X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, organizationCStr, -1, -1, 0)) { // Organization 0126 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set organization " << getSslError(); 0127 return QSslCertificate(); 0128 } 0129 0130 const unsigned char *organizationalUnitCStr = reinterpret_cast<const unsigned char *>("KDE Connect"); 0131 if (!X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, organizationalUnitCStr, -1, -1, 0)) { // Organizational Unit 0132 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set organizational unit " << getSslError(); 0133 return QSslCertificate(); 0134 } 0135 0136 if (!X509_set_subject_name(x509.get(), name)) { 0137 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set subject name" << getSslError(); 0138 return QSslCertificate(); 0139 } 0140 0141 if (!X509_set_issuer_name(x509.get(), name)) { 0142 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set issuer name" << getSslError(); 0143 return QSslCertificate(); 0144 } 0145 0146 // Set the certificate validity period. 0147 int a_year_in_seconds = 356 * 24 * 60 * 60; 0148 X509_gmtime_adj(X509_getm_notBefore(x509.get()), -a_year_in_seconds); 0149 X509_gmtime_adj(X509_getm_notAfter(x509.get()), 10 * a_year_in_seconds); 0150 0151 // Convert the QSslKey to the OpenSSL private key format. 0152 QByteArray keyPemData = qtPrivateKey.toPem(); 0153 auto bio = std::unique_ptr<BIO, decltype(&::BIO_free_all)>(BIO_new_mem_buf(keyPemData.data(), -1), ::BIO_free_all); 0154 if (!bio) { 0155 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to allocate I/O abstraction " << getSslError(); 0156 return QSslCertificate(); 0157 } 0158 0159 auto pkeyRaw = PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr); 0160 auto pkey = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>(pkeyRaw, ::EVP_PKEY_free); 0161 if (!pkey) { 0162 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to read private key " << getSslError(); 0163 return QSslCertificate(); 0164 } 0165 0166 if (!X509_set_pubkey(x509.get(), pkey.get())) { 0167 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to set private key " << getSslError(); 0168 return QSslCertificate(); 0169 } 0170 0171 // Sign the certificate with private key. 0172 if (!X509_sign(x509.get(), pkey.get(), EVP_sha256())) { 0173 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to sign certificate " << getSslError(); 0174 return QSslCertificate(); 0175 } 0176 0177 // Convert to PEM which is the format needed for QSslCertificate. 0178 bio = std::unique_ptr<BIO, decltype(&::BIO_free_all)>(BIO_new(BIO_s_mem()), ::BIO_free_all); 0179 if (!bio) { 0180 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed to allocate I/O abstraction " << getSslError(); 0181 return QSslCertificate(); 0182 } 0183 0184 if (!PEM_write_bio_X509(bio.get(), x509.get())) { 0185 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed write PEM format certificate to BIO " << getSslError(); 0186 return QSslCertificate(); 0187 } 0188 0189 BUF_MEM *pem = nullptr; 0190 if (!BIO_get_mem_ptr(bio.get(), &pem)) { 0191 qCWarning(KDECONNECT_CORE) << "Generate Self Signed Certificate failed get PEM format address " << getSslError(); 0192 return QSslCertificate(); 0193 } 0194 0195 return QSslCertificate(QByteArray(pem->data, pem->length)); 0196 } 0197 0198 } // namespace SslHelper