newcertificatewizard.cpp 62.9 KB
Newer Older
Marc Mutz's avatar
Marc Mutz committed
1
2
3
4
/* -*- mode: c++; c-basic-offset:4 -*-
    newcertificatewizard/newcertificatewizard.cpp

    This file is part of Kleopatra, the KDE keymanager
5
    SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
Marc Mutz's avatar
Marc Mutz committed
6

7
8
    SPDX-FileCopyrightText: 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
    SPDX-FileContributor: Intevation GmbH
Marc Mutz's avatar
Marc Mutz committed
9

10
    SPDX-License-Identifier: GPL-2.0-or-later
Marc Mutz's avatar
Marc Mutz committed
11
12
13
14
*/

#include <config-kleopatra.h>

15
16
17
18
#include "newcertificatewizard.h"

#include "ui_chooseprotocolpage.h"
#include "ui_enterdetailspage.h"
19
#include "ui_keycreationpage.h"
20
21
#include "ui_resultpage.h"

22
23
#include "ui_advancedsettingsdialog.h"

24
25
26
#include "commands/exportsecretkeycommand.h"
#include "commands/exportopenpgpcertstoservercommand.h"
#include "commands/exportcertificatecommand.h"
27

28
29
#include "kleopatraapplication.h"

30
31
32
#include "utils/validation.h"
#include "utils/filedialog.h"
#include "utils/keyparameters.h"
33

34
#include <Libkleo/GnuPG>
Laurent Montel's avatar
Laurent Montel committed
35
36
#include <Libkleo/Stl_Util>
#include <Libkleo/Dn>
Laurent Montel's avatar
Laurent Montel committed
37
#include <Libkleo/OidMap>
38
39
#include <Libkleo/KeyCache>
#include <Libkleo/Formatting>
40

41
42
#include <QGpgME/KeyGenerationJob>
#include <QGpgME/Protocol>
43
#include <QGpgME/CryptoConfig>
44

45
#include <gpgme++/global.h>
46
#include <gpgme++/keygenerationresult.h>
47
#include <gpgme++/context.h>
48
#include <gpgme++/interfaces/passphraseprovider.h>
49

50
#include <KConfigGroup>
Laurent Montel's avatar
Laurent Montel committed
51
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
52
#include "kleopatra_debug.h"
Laurent Montel's avatar
Laurent Montel committed
53
#include <QTemporaryDir>
54
#include <KMessageBox>
Laurent Montel's avatar
KIcon--    
Laurent Montel committed
55
#include <QIcon>
56
57
58

#include <QRegExpValidator>
#include <QLineEdit>
59
#include <QMetaProperty>
Marc Mutz's avatar
Marc Mutz committed
60
61
#include <QDir>
#include <QFile>
62
#include <QUrl>
63
#include <QDesktopServices>
64
#include <QUrlQuery>
65

66
#include <algorithm>
67

68
#include <KSharedConfig>
69
#include <KEMailSettings>
Laurent Montel's avatar
Laurent Montel committed
70
#include <QLocale>
71

72
73
74
75
76
77
#ifdef Q_OS_WIN
# include <windows.h>
# define SECURITY_WIN32
# include <secext.h> // For GetUserNameEx
#endif

78
79
using namespace Kleo;
using namespace Kleo::NewCertificateUi;
80
using namespace Kleo::Commands;
81
82
using namespace GpgME;

83
84
85
static const char RSA_KEYSIZES_ENTRY[] = "RSAKeySizes";
static const char DSA_KEYSIZES_ENTRY[] = "DSAKeySizes";
static const char ELG_KEYSIZES_ENTRY[] = "ELGKeySizes";
Marc Mutz's avatar
Marc Mutz committed
86

87
88
89
static const char RSA_KEYSIZE_LABELS_ENTRY[] = "RSAKeySizeLabels";
static const char DSA_KEYSIZE_LABELS_ENTRY[] = "DSAKeySizeLabels";
static const char ELG_KEYSIZE_LABELS_ENTRY[] = "ELGKeySizeLabels";
90

91
92
static const char PGP_KEY_TYPE_ENTRY[] = "PGPKeyType";
static const char CMS_KEY_TYPE_ENTRY[] = "CMSKeyType";
93

94
95
96
97
98
99
100
101
102
103
104
105
106
107
// This should come from gpgme in the future
// For now we only support the basic 2.1 curves and check
// for GnuPG 2.1. The whole subkey / usage generation needs
// new api and a reworked dialog. (ah 10.3.16)
// EDDSA should be supported, too.
static const QStringList curveNames {
    { QStringLiteral("brainpoolP256r1") },
    { QStringLiteral("brainpoolP384r1") },
    { QStringLiteral("brainpoolP512r1") },
    { QStringLiteral("NIST P-256") },
    { QStringLiteral("NIST P-384") },
    { QStringLiteral("NIST P-521") },
};

108
109
110
111
112
113
114
115
116
117
class EmptyPassphraseProvider: public PassphraseProvider
{
public:
    char *getPassphrase(const char * /*useridHint*/, const char * /*description*/,
                        bool /*previousWasBad*/, bool &/*canceled*/) Q_DECL_OVERRIDE
    {
        return gpgrt_strdup ("");
    }
};

Laurent Montel's avatar
Laurent Montel committed
118
119
static void set_tab_order(const QList<QWidget *> &wl)
{
120
    kdtools::for_each_adjacent_pair(wl.begin(), wl.end(), &QWidget::setTabOrder);
121
122
}

123
enum KeyAlgo { RSA, DSA, ELG, ECDSA, ECDH, EDDSA };
124

125
static bool is_algo(Subkey::PubkeyAlgo algo, KeyAlgo what)
Laurent Montel's avatar
Laurent Montel committed
126
127
{
    switch (algo) {
128
129
130
131
132
133
134
135
136
137
138
139
140
        case Subkey::AlgoRSA:
        case Subkey::AlgoRSA_E:
        case Subkey::AlgoRSA_S:
            return what == RSA;
        case Subkey::AlgoELG_E:
        case Subkey::AlgoELG:
            return what == ELG;
        case Subkey::AlgoDSA:
            return what == DSA;
        case Subkey::AlgoECDSA:
            return what == ECDSA;
        case Subkey::AlgoECDH:
            return what == ECDH;
141
142
        case Subkey::AlgoEDDSA:
            return what == EDDSA;
143
144
        default:
            break;
145
146
147
148
    }
    return false;
}

Laurent Montel's avatar
Laurent Montel committed
149
150
static bool is_rsa(unsigned int algo)
{
151
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), RSA);
152
153
}

Laurent Montel's avatar
Laurent Montel committed
154
155
static bool is_dsa(unsigned int algo)
{
156
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), DSA);
157
158
}

Laurent Montel's avatar
Laurent Montel committed
159
160
static bool is_elg(unsigned int algo)
{
161
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), ELG);
162
163
}

164
165
static bool is_ecdsa(unsigned int algo)
{
166
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), ECDSA);
167
168
}

169
170
171
172
173
static bool is_eddsa(unsigned int algo)
{
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), EDDSA);
}

174
175
static bool is_ecdh(unsigned int algo)
{
176
    return is_algo(static_cast<Subkey::PubkeyAlgo>(algo), ECDH);
177
178
}

Laurent Montel's avatar
Laurent Montel committed
179
180
static void force_set_checked(QAbstractButton *b, bool on)
{
181
182
    // work around Qt bug (tested: 4.1.4, 4.2.3, 4.3.4)
    const bool autoExclusive = b->autoExclusive();
Laurent Montel's avatar
Laurent Montel committed
183
184
185
    b->setAutoExclusive(false);
    b->setChecked(b->isEnabled() && on);
    b->setAutoExclusive(autoExclusive);
186
187
}

Laurent Montel's avatar
Laurent Montel committed
188
189
190
static void set_keysize(QComboBox *cb, unsigned int strength)
{
    if (!cb) {
191
        return;
Laurent Montel's avatar
Laurent Montel committed
192
193
194
    }
    const int idx = cb->findData(static_cast<int>(strength));
    cb->setCurrentIndex(idx);
195
196
}

Laurent Montel's avatar
Laurent Montel committed
197
198
199
static unsigned int get_keysize(const QComboBox *cb)
{
    if (!cb) {
200
        return 0;
Laurent Montel's avatar
Laurent Montel committed
201
    }
202
    const int idx = cb->currentIndex();
Laurent Montel's avatar
Laurent Montel committed
203
    if (idx < 0) {
204
        return 0;
Laurent Montel's avatar
Laurent Montel committed
205
206
    }
    return cb->itemData(idx).toInt();
207
208
}

209
210
211
212
213
static void set_curve(QComboBox *cb, const QString &curve)
{
    if (!cb) {
        return;
    }
214
    const int idx = cb->findText(curve);
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    if (idx < 0) {
        // Can't happen as we don't have them configurable.
        qCWarning(KLEOPATRA_LOG) << "curve " << curve << " not allowed";
    }
    cb->setCurrentIndex(idx);
}

static QString get_curve(const QComboBox *cb)
{
    if (!cb) {
        return QString();
    }
    return cb->currentText();
}

230
231
232
233
234
235
236
237
238
239
240
// Extract the algo information from default_pubkey_algo format
//
// and put it into the return values size, algo and curve.
//
// Values look like:
// RSA-2048
// rsa2048/cert,sign+rsa2048/enc
// brainpoolP256r1+brainpoolP256r1
static void parseAlgoString(const QString &algoString, int *size, Subkey::PubkeyAlgo *algo, QString &curve)
{
    const auto split = algoString.split(QLatin1Char('/'));
241
    bool isEncrypt = split.size() == 2 && split[1].contains(QLatin1String("enc"));
242
243
244
245
246
247
248

    // Normalize
    const auto lowered = split[0].toLower().remove(QLatin1Char('-'));
    if (!algo || !size) {
        return;
    }
    *algo = Subkey::AlgoUnknown;
Laurent Montel's avatar
Laurent Montel committed
249
    if (lowered.startsWith(QLatin1String("rsa"))) {
250
        *algo = Subkey::AlgoRSA;
Laurent Montel's avatar
Laurent Montel committed
251
    } else if (lowered.startsWith(QLatin1String("dsa"))) {
252
        *algo = Subkey::AlgoDSA;
Laurent Montel's avatar
Laurent Montel committed
253
    } else if (lowered.startsWith(QLatin1String("elg"))) {
254
255
256
257
258
        *algo = Subkey::AlgoELG;
    }

    if (*algo != Subkey::AlgoUnknown) {
        bool ok;
Laurent Montel's avatar
Laurent Montel committed
259
        *size = lowered.rightRef(lowered.size() - 3).toInt(&ok);
260
261
        if (!ok) {
            qCWarning(KLEOPATRA_LOG) << "Could not extract size from: " << lowered;
Andre Heinecke's avatar
Andre Heinecke committed
262
            *size = 3072;
263
264
265
266
267
        }
        return;
    }

    // Now the ECC Algorithms
Laurent Montel's avatar
Laurent Montel committed
268
    if (lowered.startsWith(QLatin1String("ed25519"))) {
269
270
271
272
273
274
275
        // Special handling for this as technically
        // this is a cv25519 curve used for EDDSA
        curve = split[0];
        *algo = Subkey::AlgoEDDSA;
        return;
    }

Laurent Montel's avatar
Laurent Montel committed
276
277
278
279
    if (lowered.startsWith(QLatin1String("cv25519")) ||
        lowered.startsWith(QLatin1String("nist")) ||
        lowered.startsWith(QLatin1String("brainpool")) ||
        lowered.startsWith(QLatin1String("secp"))) {
280
281
282
283
284
285
286
287
        curve = split[0];
        *algo = isEncrypt ? Subkey::AlgoECDH : Subkey::AlgoECDSA;
        return;
    }

    qCWarning(KLEOPATRA_LOG) << "Failed to parse default_pubkey_algo:" << algoString;
}

288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
/* Use Windows API to query the user name and email.
   EXTENDED_NAME_FORMAT is documented in MSDN */
#ifdef Q_OS_WIN
QString win_get_user_name (EXTENDED_NAME_FORMAT what)
{
  QString ret;
  wchar_t tmp[1];
  ULONG nSize = 1;
  if (what == NameUnknown) {
      if (GetUserNameW (tmp, &nSize)) {
          qCWarning (KLEOPATRA_LOG) << "Got empty username";
          return ret;
      }
  } else if (GetUserNameExW (what, tmp, &nSize)) {
      return ret;
  }

  /* nSize now contains the required size of the buffer */
  wchar_t *buf = new wchar_t[nSize];

  if (what == NameUnknown) {
      if (!GetUserNameW (buf, &nSize)) {
          qCWarning (KLEOPATRA_LOG) << "Failed to get username";
          delete[] buf;
          return ret;
      }
  } else if (!GetUserNameExW (what, buf, &nSize)) {
      delete[] buf;
      return ret;
  }
  ret = QString::fromWCharArray (buf, nSize);
  delete[] buf;
  return ret.trimmed();
}
#endif

324
Q_DECLARE_METATYPE(GpgME::Subkey::PubkeyAlgo)
Laurent Montel's avatar
Laurent Montel committed
325
326
327
328
329
330
331
332
namespace Kleo
{
namespace NewCertificateUi
{
class WizardPage : public QWizardPage
{
    Q_OBJECT
protected:
Laurent Montel's avatar
Laurent Montel committed
333
    explicit WizardPage(QWidget *parent = nullptr)
Laurent Montel's avatar
Laurent Montel committed
334
        : QWizardPage(parent) {}
335

Laurent Montel's avatar
Laurent Montel committed
336
337
    NewCertificateWizard *wizard() const
    {
338
        Q_ASSERT(static_cast<NewCertificateWizard *>(QWizardPage::wizard()) == qobject_cast<NewCertificateWizard *>(QWizardPage::wizard()));
Laurent Montel's avatar
Laurent Montel committed
339
340
        return static_cast<NewCertificateWizard *>(QWizardPage::wizard());
    }
341

Laurent Montel's avatar
Laurent Montel committed
342
343
    QAbstractButton *button(QWizard::WizardButton button) const
    {
Laurent Montel's avatar
Laurent Montel committed
344
        return QWizardPage::wizard() ? QWizardPage::wizard()->button(button) : nullptr;
Laurent Montel's avatar
Laurent Montel committed
345
346
347
348
349
350
351
352
    }

    bool isButtonVisible(QWizard::WizardButton button) const
    {
        if (const QAbstractButton *const b = this->button(button)) {
            return b->isVisible();
        } else {
            return false;
353
        }
Laurent Montel's avatar
Laurent Montel committed
354
    }
355

Laurent Montel's avatar
Laurent Montel committed
356
    QDir tmpDir() const;
357

Laurent Montel's avatar
Laurent Montel committed
358
359
360
361
362
protected Q_SLOTS:
    void setButtonVisible(QWizard::WizardButton button, bool visible)
    {
        if (QAbstractButton *const b = this->button(button)) {
            b->setVisible(visible);
363
        }
Laurent Montel's avatar
Laurent Montel committed
364
    }
365

Laurent Montel's avatar
Laurent Montel committed
366
protected:
Laurent Montel's avatar
Laurent Montel committed
367
#define FIELD(type, name) type name() const { return field( QStringLiteral(#name) ).value<type>(); }
Laurent Montel's avatar
Laurent Montel committed
368
369
370
371
372
373
374
375
376
    FIELD(bool, pgp)
    FIELD(bool, signingAllowed)
    FIELD(bool, encryptionAllowed)
    FIELD(bool, certificationAllowed)
    FIELD(bool, authenticationAllowed)

    FIELD(QString, name)
    FIELD(QString, email)
    FIELD(QString, dn)
377
    FIELD(bool, protectedKey)
Laurent Montel's avatar
Laurent Montel committed
378

379
    FIELD(Subkey::PubkeyAlgo, keyType)
Laurent Montel's avatar
Laurent Montel committed
380
    FIELD(int, keyStrength)
Laurent Montel's avatar
Laurent Montel committed
381
    FIELD(QString, keyCurve)
Laurent Montel's avatar
Laurent Montel committed
382

383
    FIELD(Subkey::PubkeyAlgo, subkeyType)
Laurent Montel's avatar
Laurent Montel committed
384
    FIELD(int, subkeyStrength)
Laurent Montel's avatar
Laurent Montel committed
385
    FIELD(QString, subkeyCurve)
Laurent Montel's avatar
Laurent Montel committed
386
387
388
389
390
391
392
393
394
395
396
397

    FIELD(QDate, expiryDate)

    FIELD(QStringList, additionalUserIDs)
    FIELD(QStringList, additionalEMailAddresses)
    FIELD(QStringList, dnsNames)
    FIELD(QStringList, uris)

    FIELD(QString, url)
    FIELD(QString, error)
    FIELD(QString, result)
    FIELD(QString, fingerprint)
398
#undef FIELD
Laurent Montel's avatar
Laurent Montel committed
399
};
400
401
402
403
404
} // namespace NewCertificateUi
} // namespace Kleo

using namespace Kleo::NewCertificateUi;

Laurent Montel's avatar
Laurent Montel committed
405
406
namespace
{
407

Laurent Montel's avatar
Laurent Montel committed
408
409
410
411
412
413
414
415
class AdvancedSettingsDialog : public QDialog
{
    Q_OBJECT
    Q_PROPERTY(QStringList additionalUserIDs READ additionalUserIDs WRITE setAdditionalUserIDs)
    Q_PROPERTY(QStringList additionalEMailAddresses READ additionalEMailAddresses WRITE setAdditionalEMailAddresses)
    Q_PROPERTY(QStringList dnsNames READ dnsNames WRITE setDnsNames)
    Q_PROPERTY(QStringList uris READ uris WRITE setUris)
    Q_PROPERTY(uint keyStrength READ keyStrength WRITE setKeyStrength)
416
    Q_PROPERTY(Subkey::PubkeyAlgo keyType READ keyType WRITE setKeyType)
417
    Q_PROPERTY(QString keyCurve READ keyCurve WRITE setKeyCurve)
Laurent Montel's avatar
Laurent Montel committed
418
    Q_PROPERTY(uint subkeyStrength READ subkeyStrength WRITE setSubkeyStrength)
419
    Q_PROPERTY(QString subkeyCurve READ subkeyCurve WRITE setSubkeyCurve)
420
    Q_PROPERTY(Subkey::PubkeyAlgo subkeyType READ subkeyType WRITE setSubkeyType)
Laurent Montel's avatar
Laurent Montel committed
421
422
423
424
425
426
    Q_PROPERTY(bool signingAllowed READ signingAllowed WRITE setSigningAllowed)
    Q_PROPERTY(bool encryptionAllowed READ encryptionAllowed WRITE setEncryptionAllowed)
    Q_PROPERTY(bool certificationAllowed READ certificationAllowed WRITE setCertificationAllowed)
    Q_PROPERTY(bool authenticationAllowed READ authenticationAllowed WRITE setAuthenticationAllowed)
    Q_PROPERTY(QDate expiryDate READ expiryDate WRITE setExpiryDate)
public:
Laurent Montel's avatar
Laurent Montel committed
427
    explicit AdvancedSettingsDialog(QWidget *parent = nullptr)
Laurent Montel's avatar
Laurent Montel committed
428
429
        : QDialog(parent),
          protocol(UnknownProtocol),
430
431
          pgpDefaultAlgorithm(Subkey::AlgoELG_E),
          cmsDefaultAlgorithm(Subkey::AlgoRSA),
Laurent Montel's avatar
Laurent Montel committed
432
          keyTypeImmutable(false),
433
          ui(),
434
435
          mECCSupported(engineIsVersion(2, 1, 0)),
          mEdDSASupported(engineIsVersion(2, 1, 15))
Laurent Montel's avatar
Laurent Montel committed
436
    {
437
        qRegisterMetaType<Subkey::PubkeyAlgo>("Subkey::PubkeyAlgo");
Laurent Montel's avatar
Laurent Montel committed
438
439
440
441
        ui.setupUi(this);
        const QDate today = QDate::currentDate();
        ui.expiryDE->setMinimumDate(today);
        ui.expiryDE->setDate(today.addYears(2));
442
        ui.expiryCB->setChecked(true);
Laurent Montel's avatar
Laurent Montel committed
443
444
445
446
447
448
        ui.emailLW->setDefaultValue(i18n("new email"));
        ui.dnsLW->setDefaultValue(i18n("new dns name"));
        ui.uriLW->setDefaultValue(i18n("new uri"));

        fillKeySizeComboBoxen();
    }
449

Laurent Montel's avatar
Laurent Montel committed
450
451
452
453
454
455
456
457
    void setProtocol(GpgME::Protocol proto)
    {
        if (protocol == proto) {
            return;
        }
        protocol = proto;
        loadDefaultKeyType();
    }
458

Laurent Montel's avatar
Laurent Montel committed
459
460
461
462
463
464
465
466
    void setAdditionalUserIDs(const QStringList &items)
    {
        ui.uidLW->setItems(items);
    }
    QStringList additionalUserIDs() const
    {
        return ui.uidLW->items();
    }
467

Laurent Montel's avatar
Laurent Montel committed
468
469
470
471
472
473
474
475
    void setAdditionalEMailAddresses(const QStringList &items)
    {
        ui.emailLW->setItems(items);
    }
    QStringList additionalEMailAddresses() const
    {
        return ui.emailLW->items();
    }
476

Laurent Montel's avatar
Laurent Montel committed
477
478
479
480
481
482
483
484
    void setDnsNames(const QStringList &items)
    {
        ui.dnsLW->setItems(items);
    }
    QStringList dnsNames() const
    {
        return ui.dnsLW->items();
    }
485

Laurent Montel's avatar
Laurent Montel committed
486
487
488
489
490
491
492
493
    void setUris(const QStringList &items)
    {
        ui.uriLW->setItems(items);
    }
    QStringList uris() const
    {
        return ui.uriLW->items();
    }
494

Laurent Montel's avatar
Laurent Montel committed
495
496
497
498
499
500
501
502
503
    void setKeyStrength(unsigned int strength)
    {
        set_keysize(ui.rsaKeyStrengthCB, strength);
        set_keysize(ui.dsaKeyStrengthCB, strength);
    }
    unsigned int keyStrength() const
    {
        return
            ui.dsaRB->isChecked() ? get_keysize(ui.dsaKeyStrengthCB) :
Laurent Montel's avatar
Laurent Montel committed
504
            ui.rsaRB->isChecked() ? get_keysize(ui.rsaKeyStrengthCB) : 0;
Laurent Montel's avatar
Laurent Montel committed
505
    }
506

507
    void setKeyType(Subkey::PubkeyAlgo algo)
Laurent Montel's avatar
Laurent Montel committed
508
509
510
    {
        QRadioButton *const rb =
            is_rsa(algo) ? ui.rsaRB :
511
            is_dsa(algo) ? ui.dsaRB :
512
            is_ecdsa(algo) || is_eddsa(algo) ? ui.ecdsaRB : nullptr;
Laurent Montel's avatar
Laurent Montel committed
513
514
        if (rb) {
            rb->setChecked(true);
515
        }
Laurent Montel's avatar
Laurent Montel committed
516
    }
517
    Subkey::PubkeyAlgo keyType() const
Laurent Montel's avatar
Laurent Montel committed
518
519
    {
        return
520
521
            ui.dsaRB->isChecked() ? Subkey::AlgoDSA :
            ui.rsaRB->isChecked() ? Subkey::AlgoRSA :
522
            ui.ecdsaRB->isChecked() ?
523
                ui.ecdsaKeyCurvesCB->currentText() == QLatin1String("ed25519") ? Subkey::AlgoEDDSA :
524
                Subkey::AlgoECDSA :
525
            Subkey::AlgoUnknown;
Laurent Montel's avatar
Laurent Montel committed
526
    }
527

528
529
530
531
532
533
534
535
536
537
    void setKeyCurve(const QString &curve)
    {
        set_curve(ui.ecdsaKeyCurvesCB, curve);
    }

    QString keyCurve() const
    {
        return get_curve(ui.ecdsaKeyCurvesCB);
    }

538
    void setSubkeyType(Subkey::PubkeyAlgo algo)
Laurent Montel's avatar
Laurent Montel committed
539
540
541
    {
        ui.elgCB->setChecked(is_elg(algo));
        ui.rsaSubCB->setChecked(is_rsa(algo));
542
        ui.ecdhCB->setChecked(is_ecdh(algo));
Laurent Montel's avatar
Laurent Montel committed
543
    }
544
    Subkey::PubkeyAlgo subkeyType() const
Laurent Montel's avatar
Laurent Montel committed
545
546
    {
        if (ui.elgCB->isChecked()) {
547
            return Subkey::AlgoELG_E;
Laurent Montel's avatar
Laurent Montel committed
548
        } else if (ui.rsaSubCB->isChecked()) {
549
            return Subkey::AlgoRSA;
550
        } else if (ui.ecdhCB->isChecked()) {
551
            return Subkey::AlgoECDH;
552
        }
553
        return Subkey::AlgoUnknown;
Laurent Montel's avatar
Laurent Montel committed
554
    }
555

556
557
558
559
560
561
562
563
564
565
    void setSubkeyCurve(const QString &curve)
    {
        set_curve(ui.ecdhKeyCurvesCB, curve);
    }

    QString subkeyCurve() const
    {
        return get_curve(ui.ecdhKeyCurvesCB);
    }

Laurent Montel's avatar
Laurent Montel committed
566
567
    void setSubkeyStrength(unsigned int strength)
    {
568
        if (subkeyType() == Subkey::AlgoRSA) {
Laurent Montel's avatar
Laurent Montel committed
569
570
571
            set_keysize(ui.rsaKeyStrengthSubCB, strength);
        } else {
            set_keysize(ui.elgKeyStrengthCB, strength);
572
        }
Laurent Montel's avatar
Laurent Montel committed
573
574
575
    }
    unsigned int subkeyStrength() const
    {
576
        if (subkeyType() == Subkey::AlgoRSA) {
Laurent Montel's avatar
Laurent Montel committed
577
            return get_keysize(ui.rsaKeyStrengthSubCB);
578
        }
Laurent Montel's avatar
Laurent Montel committed
579
580
        return get_keysize(ui.elgKeyStrengthCB);
    }
581

Laurent Montel's avatar
Laurent Montel committed
582
583
584
585
586
587
588
589
    void setSigningAllowed(bool on)
    {
        ui.signingCB->setChecked(on);
    }
    bool signingAllowed() const
    {
        return ui.signingCB->isChecked();
    }
590

Laurent Montel's avatar
Laurent Montel committed
591
592
593
594
595
596
597
598
    void setEncryptionAllowed(bool on)
    {
        ui.encryptionCB->setChecked(on);
    }
    bool encryptionAllowed() const
    {
        return ui.encryptionCB->isChecked();
    }
599

Laurent Montel's avatar
Laurent Montel committed
600
601
602
603
604
605
606
607
    void setCertificationAllowed(bool on)
    {
        ui.certificationCB->setChecked(on);
    }
    bool certificationAllowed() const
    {
        return ui.certificationCB->isChecked();
    }
608

Laurent Montel's avatar
Laurent Montel committed
609
610
611
612
613
614
615
616
    void setAuthenticationAllowed(bool on)
    {
        ui.authenticationCB->setChecked(on);
    }
    bool authenticationAllowed() const
    {
        return ui.authenticationCB->isChecked();
    }
617

Laurent Montel's avatar
Laurent Montel committed
618
    void setExpiryDate(QDate date)
Laurent Montel's avatar
Laurent Montel committed
619
620
621
622
623
624
625
626
627
    {
        if (date.isValid()) {
            ui.expiryDE->setDate(date);
        } else {
            ui.expiryCB->setChecked(false);
        }
    }
    QDate expiryDate() const
    {
Laurent Montel's avatar
Laurent Montel committed
628
        return ui.expiryCB->isChecked() ? ui.expiryDE->date() : QDate();
Laurent Montel's avatar
Laurent Montel committed
629
    }
630

Laurent Montel's avatar
Laurent Montel committed
631
632
Q_SIGNALS:
    void changed();
633

Laurent Montel's avatar
Laurent Montel committed
634
635
636
637
638
private Q_SLOTS:
    void slotKeyMaterialSelectionChanged()
    {
        const unsigned int algo = keyType();
        const unsigned int sk_algo = subkeyType();
639

Laurent Montel's avatar
Laurent Montel committed
640
641
642
        if (protocol == OpenPGP) {
            if (!keyTypeImmutable) {
                ui.elgCB->setEnabled(is_dsa(algo));
643
                ui.rsaSubCB->setEnabled(is_rsa(algo));
644
                ui.ecdhCB->setEnabled(is_ecdsa(algo) || is_eddsa(algo));
645
                if (sender() == ui.dsaRB || sender() == ui.rsaRB || sender() == ui.ecdsaRB) {
Laurent Montel's avatar
Laurent Montel committed
646
                    ui.elgCB->setChecked(is_dsa(algo));
647
                    ui.ecdhCB->setChecked(is_ecdsa(algo) || is_eddsa(algo));
648
                    ui.rsaSubCB->setChecked(is_rsa(algo));
Thomas McGuire's avatar
Thomas McGuire committed
649
                }
Laurent Montel's avatar
Laurent Montel committed
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
                if (is_rsa(algo)) {
                    ui.encryptionCB->setEnabled(true);
                    ui.encryptionCB->setChecked(true);
                    ui.signingCB->setEnabled(true);
                    ui.signingCB->setChecked(true);
                    ui.authenticationCB->setEnabled(true);
                    if (is_rsa(sk_algo)) {
                        ui.encryptionCB->setEnabled(false);
                        ui.encryptionCB->setChecked(true);
                    } else {
                        ui.encryptionCB->setEnabled(true);
                    }
                } else if (is_dsa(algo)) {
                    ui.encryptionCB->setEnabled(false);
                    if (is_elg(sk_algo)) {
                        ui.encryptionCB->setChecked(true);
666
                    } else {
Laurent Montel's avatar
Laurent Montel committed
667
                        ui.encryptionCB->setChecked(false);
668
                    }
669
                } else if (is_ecdsa(algo) || is_eddsa(algo)) {
670
671
672
673
674
                    ui.signingCB->setEnabled(true);
                    ui.signingCB->setChecked(true);
                    ui.authenticationCB->setEnabled(true);
                    ui.encryptionCB->setEnabled(false);
                    ui.encryptionCB->setChecked(is_ecdh(sk_algo));
675
676
                }
            }
Laurent Montel's avatar
Laurent Montel committed
677
678
        } else {
            //assert( is_rsa( keyType() ) ); // it can happen through misconfiguration by the admin that no key type is selectable at all
679
        }
Laurent Montel's avatar
Laurent Montel committed
680
    }
681

Laurent Montel's avatar
Laurent Montel committed
682
683
684
685
    void slotSigningAllowedToggled(bool on)
    {
        if (!on && protocol == CMS && !encryptionAllowed()) {
            setEncryptionAllowed(true);
686
        }
Laurent Montel's avatar
Laurent Montel committed
687
688
689
690
691
    }
    void slotEncryptionAllowedToggled(bool on)
    {
        if (!on && protocol == CMS && !signingAllowed()) {
            setSigningAllowed(true);
692
        }
Laurent Montel's avatar
Laurent Montel committed
693
    }
694

Laurent Montel's avatar
Laurent Montel committed
695
696
697
private:
    void fillKeySizeComboBoxen();
    void loadDefaultKeyType();
698
    void loadDefaultGnuPGKeyType();
Laurent Montel's avatar
Laurent Montel committed
699
    void updateWidgetVisibility();
700

Laurent Montel's avatar
Laurent Montel committed
701
702
703
704
705
706
private:
    GpgME::Protocol protocol;
    unsigned int pgpDefaultAlgorithm;
    unsigned int cmsDefaultAlgorithm;
    bool keyTypeImmutable;
    Ui_AdvancedSettingsDialog ui;
707
    bool mECCSupported;
708
    bool mEdDSASupported;
Laurent Montel's avatar
Laurent Montel committed
709
};
710

Laurent Montel's avatar
Laurent Montel committed
711
712
713
714
class ChooseProtocolPage : public WizardPage
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
715
    explicit ChooseProtocolPage(QWidget *p = nullptr)
Laurent Montel's avatar
Laurent Montel committed
716
717
718
719
720
        : WizardPage(p),
          initialized(false),
          ui()
    {
        ui.setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
721
        registerField(QStringLiteral("pgp"), ui.pgpCLB);
Laurent Montel's avatar
Laurent Montel committed
722
    }
723

Laurent Montel's avatar
Laurent Montel committed
724
725
726
727
728
729
730
731
732
    void setProtocol(Protocol proto)
    {
        if (proto == OpenPGP) {
            ui.pgpCLB->setChecked(true);
        } else if (proto == CMS) {
            ui.x509CLB->setChecked(true);
        } else {
            force_set_checked(ui.pgpCLB,  false);
            force_set_checked(ui.x509CLB, false);
733
        }
Laurent Montel's avatar
Laurent Montel committed
734
    }
735

Laurent Montel's avatar
Laurent Montel committed
736
737
738
739
    Protocol protocol() const
    {
        return
            ui.pgpCLB->isChecked()  ? OpenPGP :
Laurent Montel's avatar
Laurent Montel committed
740
            ui.x509CLB->isChecked() ? CMS : UnknownProtocol;
Laurent Montel's avatar
Laurent Montel committed
741
    }
742

743
    void initializePage() override {
Laurent Montel's avatar
Laurent Montel committed
744
745
        if (!initialized)
        {
746
747
            connect(ui.pgpCLB,  &QAbstractButton::clicked, wizard(), &QWizard::next, Qt::QueuedConnection);
            connect(ui.x509CLB, &QAbstractButton::clicked, wizard(), &QWizard::next, Qt::QueuedConnection);
748
        }
Laurent Montel's avatar
Laurent Montel committed
749
750
        initialized = true;
    }
751

752
    bool isComplete() const override
Laurent Montel's avatar
Laurent Montel committed
753
    {
Laurent Montel's avatar
Laurent Montel committed
754
        return protocol() != UnknownProtocol;
Laurent Montel's avatar
Laurent Montel committed
755
    }
756

Laurent Montel's avatar
Laurent Montel committed
757
758
759
760
private:
    bool initialized : 1;
    Ui_ChooseProtocolPage ui;
};
761

Laurent Montel's avatar
Laurent Montel committed
762
763
764
765
766
767
struct Line {
    QString attr;
    QString label;
    QString regex;
    QLineEdit *edit;
};
768

Laurent Montel's avatar
Laurent Montel committed
769
770
771
772
class EnterDetailsPage : public WizardPage
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
773
    explicit EnterDetailsPage(QWidget *p = nullptr)
Laurent Montel's avatar
Laurent Montel committed
774
775
776
777
778
        : WizardPage(p), dialog(this), ui()
    {
        ui.setupUi(this);

        // set errorLB to have a fixed height of two lines:
779
        ui.errorLB->setText(QStringLiteral("2<br>1"));
Laurent Montel's avatar
Laurent Montel committed
780
781
782
        ui.errorLB->setFixedHeight(ui.errorLB->minimumSizeHint().height());
        ui.errorLB->clear();

783
784
        connect(ui.resultLE, &QLineEdit::textChanged,
                this, &QWizardPage::completeChanged);
Laurent Montel's avatar
Laurent Montel committed
785
        // The email doesn't necessarily show up in ui.resultLE:
786
787
        connect(ui.emailLE, &QLineEdit::textChanged,
                this, &QWizardPage::completeChanged);
Laurent Montel's avatar
Laurent Montel committed
788
        registerDialogPropertiesAsFields();
Laurent Montel's avatar
Laurent Montel committed
789
790
791
        registerField(QStringLiteral("dn"), ui.resultLE);
        registerField(QStringLiteral("name"), ui.nameLE);
        registerField(QStringLiteral("email"), ui.emailLE);
792
        registerField(QStringLiteral("protectedKey"), ui.withPassCB);
Laurent Montel's avatar
Laurent Montel committed
793
        updateForm();
794
795
        setCommitPage(true);
        setButtonText(QWizard::CommitButton, i18nc("@action", "Create"));
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813

        const auto conf = QGpgME::cryptoConfig();
        if (!conf) {
            qCWarning(KLEOPATRA_LOG) << "Failed to obtain cryptoConfig.";
            return;
        }
        const auto entry = conf->entry(QStringLiteral("gpg-agent"),
                                   QStringLiteral("Passphrase policy"),
                                   QStringLiteral("enforce-passphrase-constraints"));
        if (entry && entry->boolValue()) {
            qCDebug(KLEOPATRA_LOG) << "Disabling passphrace cb because of agent config.";
            ui.withPassCB->setEnabled(false);
            ui.withPassCB->setChecked(true);
        } else {
            const KConfigGroup config(KSharedConfig::openConfig(), "CertificateCreationWizard");
            ui.withPassCB->setChecked(config.readEntry("WithPassphrase", false));
            ui.withPassCB->setEnabled(!config.isEntryImmutable("WithPassphrase"));
        }
Laurent Montel's avatar
Laurent Montel committed
814
    }
815

816
817
    bool isComplete() const override;
    void initializePage() override {
Laurent Montel's avatar
Laurent Montel committed
818
819
820
        updateForm();
        dialog.setProtocol(pgp() ? OpenPGP : CMS);
    }
821
    void cleanupPage() override {
Laurent Montel's avatar
Laurent Montel committed
822
823
        saveValues();
    }
824

Laurent Montel's avatar
Laurent Montel committed
825
826
827
828
829
private:
    void updateForm();
    void clearForm();
    void saveValues();
    void registerDialogPropertiesAsFields();
Marc Mutz's avatar
Marc Mutz committed
830

Laurent Montel's avatar
Laurent Montel committed
831
832
833
private:
    QString pgpUserID() const;
    QString cmsDN() const;
Marc Mutz's avatar
Marc Mutz committed
834

Laurent Montel's avatar
Laurent Montel committed
835
836
837
838
839
840
private Q_SLOTS:
    void slotAdvancedSettingsClicked();
    void slotUpdateResultLabel()
    {
        ui.resultLE->setText(pgp() ? pgpUserID() : cmsDN());
    }
841

Laurent Montel's avatar
Laurent Montel committed
842
843
844
845
846
847
848
private:
    QVector<Line> lineList;
    QList<QWidget *> dynamicWidgets;
    QMap<QString, QString> savedValues;
    AdvancedSettingsDialog dialog;
    Ui_EnterDetailsPage ui;
};
849

Laurent Montel's avatar
Laurent Montel committed
850
851
852
853
class KeyCreationPage : public WizardPage
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
854
    explicit KeyCreationPage(QWidget *p = nullptr)
Laurent Montel's avatar
Laurent Montel committed
855
856
857
858
859
860
        : WizardPage(p),
          ui()
    {
        ui.setupUi(this);
    }

861
    bool isComplete() const override
Laurent Montel's avatar
Laurent Montel committed
862
863
864
865
    {
        return !job;
    }

866
    void initializePage() override {
Laurent Montel's avatar
Laurent Montel committed
867
868
869
870
871
872
        startJob();
    }

private:
    void startJob()
    {
Andre Heinecke's avatar
Andre Heinecke committed
873
        const auto proto = pgp() ? QGpgME::openpgp() : QGpgME::smime();
Laurent Montel's avatar
Laurent Montel committed
874
875
876
        if (!proto) {
            return;
        }
877
        QGpgME::KeyGenerationJob *const j = proto->keyGenerationJob();
Laurent Montel's avatar
Laurent Montel committed
878
879
        if (!j) {
            return;
880
        }
881
882
883
884
885
        if (!protectedKey ()) {
            auto ctx = QGpgME::Job::context(j);
            ctx->setPassphraseProvider(&mEmptyPWProvider);
            ctx->setPinentryMode(Context::PinentryLoopback);
        }
Laurent Montel's avatar
Laurent Montel committed
886
887
        connect(j, &QGpgME::KeyGenerationJob::result,
                this, &KeyCreationPage::slotResult);
Laurent Montel's avatar
Laurent Montel committed
888
        if (const Error err = j->start(createGnupgKeyParms()))
889
            setField(QStringLiteral("error"), i18n("Could not start key pair creation: %1",
Laurent Montel's avatar
Laurent Montel committed
890
                                                   QString::fromLocal8Bit(err.asString())));
Laurent Montel's avatar
Laurent Montel committed
891
892
893
894
895
896
897
        else {
            job = j;
        }
    }
    QStringList keyUsages() const;
    QStringList subkeyUsages() const;
    QString createGnupgKeyParms() const;
898
    EmptyPassphraseProvider mEmptyPWProvider;
899

Laurent Montel's avatar
Laurent Montel committed
900
901
902
private Q_SLOTS:
    void slotResult(const GpgME::KeyGenerationResult &result, const QByteArray &request, const QString &auditLog)
    {
Laurent Montel's avatar
Laurent Montel committed
903
        Q_UNUSED(auditLog)
Andre Heinecke's avatar
Andre Heinecke committed
904
        if (result.error().code() || (pgp() && !result.fingerprint())) {
Laurent Montel's avatar
Laurent Montel committed
905
            setField(QStringLiteral("error"), result.error().isCanceled()
Laurent Montel's avatar
Laurent Montel committed
906
                     ? i18n("Operation canceled.")
907
                     : i18n("Could not create key pair: %1",
Laurent Montel's avatar
Laurent Montel committed
908
                            QString::fromLocal8Bit(result.error().asString())));
909
910
            setField(QStringLiteral("url"), QString());
            setField(QStringLiteral("result"), QString());
Laurent Montel's avatar
Laurent Montel committed
911
        } else if (pgp()) {
912
913
            setField(QStringLiteral("error"), QString());
            setField(QStringLiteral("url"), QString());
914
            setField(QStringLiteral("result"), i18n("Key pair created successfully.\n"
Laurent Montel's avatar
Laurent Montel committed
915
                                                    "Fingerprint: %1", QLatin1String(result.fingerprint())));
Laurent Montel's avatar
Laurent Montel committed
916
        } else {
917
            QFile file(tmpDir().absoluteFilePath(QStringLiteral("request.p10")));
918

Laurent Montel's avatar
Laurent Montel committed
919
            if (!file.open(QIODevice::WriteOnly)) {
920
                setField(QStringLiteral("error"), i18n("Could not write output file %1: %2",
Laurent Montel's avatar
Laurent Montel committed
921
                                                       file.fileName(), file.errorString()));
922
923
                setField(QStringLiteral("url"), QString());
                setField(QStringLiteral("result"), QString());
924
            } else {
Laurent Montel's avatar
Laurent Montel committed
925
                file.write(request);
926
927
                setField(QStringLiteral("error"), QString());
                setField(QStringLiteral("url"), QUrl::fromLocalFile(file.fileName()).toString());
928
                setField(QStringLiteral("result"), i18n("Key pair created successfully."));
929
            }
Laurent Montel's avatar
Laurent Montel committed
930
        }
931
        // Ensure that we have the key in the keycache
Andre Heinecke's avatar
Andre Heinecke committed
932
        if (pgp() && !result.error().code() && result.fingerprint()) {
933
934
935
936
            auto ctx = Context::createForProtocol(OpenPGP);
            if (ctx) {
                // Check is pretty useless something very buggy in that case.
                Error e;
Andre Heinecke's avatar
Andre Heinecke committed
937
938
939
940
941
942
                const auto key = ctx->key(result.fingerprint(), e, true);
                if (!key.isNull()) {
                    KeyCache::mutableInstance()->insert(key);
                } else {
                    qCDebug(KLEOPATRA_LOG) << "Failed to find newly generated key.";
                }
943
944
                delete ctx;
            }
945
        }
Andre Heinecke's avatar
Andre Heinecke committed
946
947
        setField(QStringLiteral("fingerprint"), result.fingerprint() ?
                 QString::fromLatin1(result.fingerprint()) : QString());
Laurent Montel's avatar
Laurent Montel committed
948
        job = nullptr;
Laurent Montel's avatar
Laurent Montel committed
949
        Q_EMIT completeChanged();
950
951
952
953
954
955
956
957
958
959
960
961
        const KConfigGroup config(KSharedConfig::openConfig(), "CertificateCreationWizard");
        if (config.readEntry("SkipResultPage", false)) {
            if (result.fingerprint()) {
                KleopatraApplication::instance()->slotActivateRequested(QStringList() <<
                       QStringLiteral("kleopatra") << QStringLiteral("--query") << QLatin1String(result.fingerprint()), QString());
                QMetaObject::invokeMethod(wizard(), "close", Qt::QueuedConnection);
            } else {
                QMetaObject::invokeMethod(wizard(), "next", Qt::QueuedConnection);
            }
        } else {
            QMetaObject::invokeMethod(wizard(), "next", Qt::QueuedConnection);
        }
Laurent Montel's avatar
Laurent Montel committed
962
963
964
    }

private:
965
    QPointer<QGpgME::KeyGenerationJob> job;
Laurent Montel's avatar
Laurent Montel committed
966
967
    Ui_KeyCreationPage ui;
};
968

Laurent Montel's avatar
Laurent Montel committed
969
970
971
972
class ResultPage : public WizardPage
{
    Q_OBJECT
public:
Laurent Montel's avatar
Laurent Montel committed
973
    explicit ResultPage(QWidget *p = nullptr)
Laurent Montel's avatar
Laurent Montel committed
974
975
976
977
978
979
980
        : WizardPage(p),
          initialized(false),
          successfullyCreatedSigningCertificate(false),
          successfullyCreatedEncryptionCertificate(false),
          ui()
    {
        ui.setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
981
        ui.dragQueen->setPixmap(QIcon::fromTheme(QStringLiteral("kleopatra")).pixmap(64, 64));
Laurent Montel's avatar
Laurent Montel committed
982
983
984
        registerField(QStringLiteral("error"),  ui.errorTB,   "plainText");
        registerField(QStringLiteral("result"), ui.resultTB,  "plainText");
        registerField(QStringLiteral("url"),    ui.dragQueen, "url");
Laurent Montel's avatar
Laurent Montel committed
985
986
987
        // hidden field, since QWizard can't deal with non-widget-backed fields...
        QLineEdit *le = new QLineEdit(this);
        le->hide();
Laurent Montel's avatar
Laurent Montel committed
988
        registerField(QStringLiteral("fingerprint"), le);
Laurent Montel's avatar
Laurent Montel committed
989
990
    }

991
    void initializePage() override {
Laurent Montel's avatar
Laurent Montel committed
992
993
        const bool error = isError();

Laurent Montel's avatar
Laurent Montel committed
994
995
        if (error)
        {
Laurent Montel's avatar
Laurent Montel committed
996
997
998
999
1000
1001
1002
1003
1004
            setTitle(i18nc("@title", "Key Creation Failed"));
            setSubTitle(i18n("Key pair creation failed. Please find details about the failure below."));
        } else {
            setTitle(i18nc("@title", "Key Pair Successfully Created"));
            setSubTitle(i18n("Your new key pair was created successfully. Please find details on the result and some suggested next steps below."));
        }

        ui.resultTB                 ->setVisible(!error);
        ui.errorTB                  ->setVisible(error);
Laurent Montel's avatar
Laurent Montel committed
1005
        ui.dragQueen                ->setVisible(!error &&!pgp());
Laurent Montel's avatar
Laurent Montel committed
1006
1007
1008
1009
        ui.restartWizardPB          ->setVisible(error);
        ui.nextStepsGB              ->setVisible(!error);
        ui.saveRequestToFilePB      ->setVisible(!pgp());
        ui.makeBackupPB             ->setVisible(pgp());
Laurent Montel's avatar
Laurent Montel committed
1010
        ui.createRevocationRequestPB->setVisible(pgp() &&false);     // not implemented
1011

Laurent Montel's avatar
Laurent Montel committed
1012
1013
1014
        ui.sendCertificateByEMailPB ->setVisible(pgp());
        ui.sendRequestByEMailPB     ->setVisible(!pgp());
        ui.uploadToKeyserverPB      ->setVisible(pgp());
1015

Laurent Montel's avatar
Laurent Montel committed
1016
1017
        if (!error && !pgp())
        {
Laurent Montel's avatar
Laurent Montel committed
1018
1019
1020
1021
1022
1023
            if (signingAllowed() && !encryptionAllowed()) {
                successfullyCreatedSigningCertificate = true;
            } else if (!signingAllowed() && encryptionAllowed()) {
                successfullyCreatedEncryptionCertificate = true;
            } else {
                successfullyCreatedEncryptionCertificate = successfullyCreatedSigningCertificate = true;
1024
            }
Laurent Montel's avatar
Laurent Montel committed
1025
        }
1026

Laurent Montel's avatar
Laurent Montel committed
1027
1028
        ui.createSigningCertificatePB->setVisible(successfullyCreatedEncryptionCertificate &&!successfullyCreatedSigningCertificate);
        ui.createEncryptionCertificatePB->setVisible(successfullyCreatedSigningCertificate &&!successfullyCreatedEncryptionCertificate);
1029

Laurent Montel's avatar
Laurent Montel committed
1030
        setButtonVisible(QWizard::CancelButton, error);
1031

Laurent Montel's avatar
Laurent Montel committed
1032
        if (!initialized)
1033
1034
            connect(ui.restartWizardPB, &QAbstractButton::clicked,
                    wizard(), &QWizard::restart);
Laurent Montel's avatar
Laurent Montel committed
1035
1036
        initialized = true;
    }
1037

Laurent Montel's avatar