File indexing completed on 2024-05-05 16:10:20
0001 /* This file is part of the KDE project 0002 * 0003 * Copyright (C) 2001 George Staikos <staikos@kde.org> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "ksslkeygen.h" 0022 #include "ksslkeygen_p.h" 0023 #include "ui_keygenwizard.h" 0024 0025 #include <klocalizedstring.h> 0026 #include <kmessagebox.h> 0027 #include <kopenssl.h> 0028 #include <kwallet.h> 0029 0030 #include <QProgressDialog> 0031 #include <QStandardPaths> 0032 #include <qplatformdefs.h> 0033 #include <qtemporaryfile.h> 0034 0035 #include <assert.h> 0036 0037 KSSLKeyGenWizardPage2::KSSLKeyGenWizardPage2(QWidget *parent) 0038 : QWizardPage(parent) 0039 { 0040 ui2 = new Ui_KGWizardPage2; 0041 ui2->setupUi(this); 0042 connect(ui2->_password1, SIGNAL(textChanged(QString)), this, SLOT(slotPassChanged())); 0043 connect(ui2->_password2, SIGNAL(textChanged(QString)), this, SLOT(slotPassChanged())); 0044 } 0045 0046 bool KSSLKeyGenWizardPage2::isComplete() const 0047 { 0048 return ui2->_password1->text() == ui2->_password2->text() && ui2->_password1->text().length() >= 4; 0049 } 0050 0051 void KSSLKeyGenWizardPage2::slotPassChanged() 0052 { 0053 emit completeChanged(); // well maybe it hasn't changed, but it might have; QWizard calls isComplete() to find out 0054 } 0055 0056 QString KSSLKeyGenWizardPage2::password() const 0057 { 0058 Q_ASSERT(isComplete()); 0059 return ui2->_password1->text(); 0060 } 0061 0062 //// 0063 0064 class KSSLKeyGenPrivate 0065 { 0066 public: 0067 KSSLKeyGenPrivate() 0068 : idx(-1) 0069 { 0070 } 0071 int idx; 0072 Ui_KGWizardPage1 *ui1; 0073 KSSLKeyGenWizardPage2 *page2; 0074 }; 0075 0076 KSSLKeyGen::KSSLKeyGen(QWidget *parent) 0077 : QWizard(parent), d(new KSSLKeyGenPrivate) 0078 { 0079 #if KSSL_HAVE_SSL 0080 0081 QWizardPage *page1 = new QWizardPage(this); 0082 page1->setTitle(i18n("KDE Certificate Request")); 0083 d->ui1 = new Ui_KGWizardPage1; 0084 d->ui1->setupUi(page1); 0085 addPage(page1); 0086 //setHelpEnabled(page1, false); 0087 0088 d->page2 = new KSSLKeyGenWizardPage2(this); 0089 d->page2->setTitle(i18n("KDE Certificate Request - Password")); 0090 addPage(d->page2); 0091 #else 0092 // tell him he doesn't have SSL 0093 #endif 0094 } 0095 0096 KSSLKeyGen::~KSSLKeyGen() 0097 { 0098 delete d->ui1; 0099 delete d; 0100 } 0101 0102 bool KSSLKeyGen::validateCurrentPage() 0103 { 0104 if (currentPage() != d->page2) { 0105 return true; 0106 } 0107 0108 assert(d->idx >= 0 && d->idx <= 3); // for now 0109 0110 // Generate the CSR 0111 int bits; 0112 switch (d->idx) { 0113 case 0: 0114 bits = 2048; 0115 break; 0116 case 1: 0117 bits = 1024; 0118 break; 0119 case 2: 0120 bits = 768; 0121 break; 0122 case 3: 0123 bits = 512; 0124 break; 0125 default: 0126 KMessageBox::error(this, i18n("Unsupported key size."), i18n("KDE SSL Information")); 0127 return false; 0128 } 0129 0130 QProgressDialog *kpd = new QProgressDialog(this); 0131 kpd->setObjectName("progress dialog"); 0132 kpd->setWindowTitle(i18n("KDE")); 0133 kpd->setLabelText(i18n("Please wait while the encryption keys are generated...")); 0134 kpd->setRange(0, 100); 0135 kpd->setValue(0); 0136 kpd->show(); 0137 // FIXME - progress dialog won't show this way 0138 0139 int rc = generateCSR("This CSR" /*FIXME */, d->page2->password(), bits, 0x10001 /* This is the traditional exponent used */); 0140 if (rc != 0) { // error 0141 return false; 0142 } 0143 0144 kpd->setValue(100); 0145 0146 #if 0 // TODO: implement 0147 if (rc == 0 && KWallet::Wallet::isEnabled()) { 0148 rc = KMessageBox::questionTwoActions(this, i18n("Do you wish to store the passphrase in your wallet file?"), QString(), KGuiItem(i18n("Store")), KGuiItem(i18n("Do Not Store"))); 0149 if (rc == KMessageBox::PrimaryAction) { 0150 KWallet::Wallet *w = KWallet::Wallet::openWallet(KWallet::Wallet::LocalWallet(), effectiveWinId()); 0151 if (w) { 0152 // FIXME: store passphrase in wallet 0153 delete w; 0154 } 0155 } 0156 } 0157 #endif 0158 0159 kpd->deleteLater(); 0160 return true; 0161 } 0162 0163 int KSSLKeyGen::generateCSR(const QString &name, const QString &pass, int bits, int e) 0164 { 0165 #if KSSL_HAVE_SSL 0166 KOSSL *kossl = KOSSL::self(); 0167 int rc; 0168 0169 X509_REQ *req = kossl->X509_REQ_new(); 0170 if (!req) { 0171 return -2; 0172 } 0173 0174 EVP_PKEY *pkey = kossl->EVP_PKEY_new(); 0175 if (!pkey) { 0176 kossl->X509_REQ_free(req); 0177 return -4; 0178 } 0179 0180 RSA *rsakey = kossl->RSA_generate_key(bits, e, nullptr, nullptr); 0181 if (!rsakey) { 0182 kossl->X509_REQ_free(req); 0183 kossl->EVP_PKEY_free(pkey); 0184 return -3; 0185 } 0186 0187 rc = kossl->EVP_PKEY_assign(pkey, EVP_PKEY_RSA, (char *)rsakey); 0188 0189 rc = kossl->X509_REQ_set_pubkey(req, pkey); 0190 0191 // Set the subject 0192 X509_NAME *n = kossl->X509_NAME_new(); 0193 0194 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_countryName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0195 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_organizationName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0196 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_organizationalUnitName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0197 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_localityName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0198 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_stateOrProvinceName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0199 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_commonName, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0200 kossl->X509_NAME_add_entry_by_txt(n, (char *)LN_pkcs9_emailAddress, MBSTRING_UTF8, (unsigned char *)name.toLocal8Bit().data(), -1, -1, 0); 0201 0202 rc = kossl->X509_REQ_set_subject_name(req, n); 0203 0204 rc = kossl->X509_REQ_sign(req, pkey, kossl->EVP_md5()); 0205 0206 // We write it to the database and then the caller can obtain it 0207 // back from there. Yes it's inefficient, but it doesn't happen 0208 // often and this way things are uniform. 0209 0210 const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kssl"; 0211 QTemporaryFile csrFile(path + "csr_XXXXXX.der"); 0212 csrFile.setAutoRemove(false); 0213 0214 if (!csrFile.open()) { 0215 kossl->X509_REQ_free(req); 0216 kossl->EVP_PKEY_free(pkey); 0217 return -5; 0218 } 0219 0220 QTemporaryFile p8File(path + "pkey_XXXXXX.p8"); 0221 p8File.setAutoRemove(false); 0222 0223 if (!p8File.open()) { 0224 kossl->X509_REQ_free(req); 0225 kossl->EVP_PKEY_free(pkey); 0226 return -5; 0227 } 0228 0229 FILE *csr_fs = QT_FOPEN(QFile::encodeName(csrFile.fileName()), "r+"); 0230 FILE *p8_fs = QT_FOPEN(QFile::encodeName(p8File.fileName()), "r+"); 0231 0232 kossl->i2d_X509_REQ_fp(csr_fs, req); 0233 0234 kossl->i2d_PKCS8PrivateKey_fp(p8_fs, pkey, 0235 kossl->EVP_bf_cbc(), pass.toLocal8Bit().data(), 0236 pass.length(), nullptr, nullptr); 0237 0238 // FIXME Write kconfig entry to store the filenames under the md5 hash 0239 0240 kossl->X509_REQ_free(req); 0241 kossl->EVP_PKEY_free(pkey); 0242 0243 fclose(csr_fs); 0244 fclose(p8_fs); 0245 0246 return 0; 0247 #else 0248 return -1; 0249 #endif 0250 } 0251 0252 QStringList KSSLKeyGen::supportedKeySizes() 0253 { 0254 QStringList x; 0255 0256 #if KSSL_HAVE_SSL 0257 x << i18n("2048 (High Grade)") 0258 << i18n("1024 (Medium Grade)") 0259 << i18n("768 (Low Grade)") 0260 << i18n("512 (Low Grade)"); 0261 #else 0262 x << i18n("No SSL support."); 0263 #endif 0264 0265 return x; 0266 } 0267 0268 void KSSLKeyGen::setKeySize(int idx) 0269 { 0270 d->idx = idx; 0271 } 0272 0273 #include "moc_ksslkeygen.cpp" 0274 0275 #include "moc_ksslkeygen_p.cpp"