• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kleopatra

  • sources
  • kde-4.12
  • kdepim
  • kleopatra
  • newcertificatewizard
newcertificatewizard.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  newcertificatewizard/newcertificatewizard.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2008 Klarälvdalens Datakonsult AB
6 
7  Kleopatra is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  Kleopatra is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  In addition, as a special exception, the copyright holders give
22  permission to link the code of this program with any edition of
23  the Qt library by Trolltech AS, Norway (or with modified versions
24  of Qt that use the same license as Qt), and distribute linked
25  combinations including the two. You must obey the GNU General
26  Public License in all respects for all of the code used other than
27  Qt. If you modify this file, you may extend this exception to
28  your version of the file, but you are not obligated to do so. If
29  you do not wish to do so, delete this exception statement from
30  your version.
31 */
32 
33 #include <config-kleopatra.h>
34 
35 #include "newcertificatewizard.h"
36 
37 #include "ui_chooseprotocolpage.h"
38 #include "ui_enterdetailspage.h"
39 #include "ui_overviewpage.h"
40 #include "ui_keycreationpage.h"
41 #include "ui_resultpage.h"
42 
43 #include "ui_advancedsettingsdialog.h"
44 
45 #include <models/keycache.h>
46 
47 #include <commands/exportsecretkeycommand.h>
48 #include <commands/exportopenpgpcertstoservercommand.h>
49 #include <commands/exportcertificatecommand.h>
50 
51 #include <utils/formatting.h>
52 #include <utils/validation.h>
53 #include <utils/filedialog.h>
54 
55 #include <kleo/stl_util.h>
56 #include <kleo/dn.h>
57 #include <kleo/oidmap.h>
58 #include <kleo/keygenerationjob.h>
59 #include <kleo/cryptobackendfactory.h>
60 #include <kleo/cryptobackend.h>
61 
62 #include <gpgme++/global.h>
63 #include <gpgme++/keygenerationresult.h>
64 #include <gpgme.h>
65 
66 #include <KConfigGroup>
67 #include <KGlobal>
68 #include <KLocale>
69 #include <KDebug>
70 #include <KTempDir>
71 #include <KMessageBox>
72 
73 #include <QRegExpValidator>
74 #include <QLineEdit>
75 #include <QMetaProperty>
76 #include <QDir>
77 #include <QFile>
78 #include <QUrl>
79 #include <QDesktopServices>
80 
81 #include <boost/range.hpp>
82 
83 #include <algorithm>
84 
85 using namespace Kleo;
86 using namespace Kleo::NewCertificateUi;
87 using namespace Kleo::Commands;
88 using namespace GpgME;
89 using namespace boost;
90 
91 static const char RSA_KEYSIZES_ENTRY[] = "RSAKeySizes";
92 static const char DSA_KEYSIZES_ENTRY[] = "DSAKeySizes";
93 static const char ELG_KEYSIZES_ENTRY[] = "ELGKeySizes";
94 
95 static const char RSA_KEYSIZE_LABELS_ENTRY[] = "RSAKeySizeLabels";
96 static const char DSA_KEYSIZE_LABELS_ENTRY[] = "DSAKeySizeLabels";
97 static const char ELG_KEYSIZE_LABELS_ENTRY[] = "ELGKeySizeLabels";
98 
99 static const char PGP_KEY_TYPE_ENTRY[] = "PGPKeyType";
100 static const char CMS_KEY_TYPE_ENTRY[] = "CMSKeyType";
101 
102 static void set_tab_order( const QList<QWidget*> & wl ) {
103  kdtools::for_each_adjacent_pair( wl, &QWidget::setTabOrder );
104 }
105 
106 enum KeyAlgo { RSA, DSA, ELG };
107 
108 static bool is_algo( gpgme_pubkey_algo_t algo, KeyAlgo what ) {
109  switch ( algo ) {
110  case GPGME_PK_RSA:
111  case GPGME_PK_RSA_E:
112  case GPGME_PK_RSA_S:
113  return what == RSA;
114  case GPGME_PK_ELG_E:
115  case GPGME_PK_ELG:
116  return what == ELG;
117  case GPGME_PK_DSA:
118  return what == DSA;
119  default:
120  break;
121  }
122  return false;
123 }
124 
125 static bool is_rsa( unsigned int algo ) {
126  return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ), RSA );
127 }
128 
129 static bool is_dsa( unsigned int algo ) {
130  return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ), DSA );
131 }
132 
133 static bool is_elg( unsigned int algo ) {
134  return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ), ELG );
135 }
136 
137 static void force_set_checked( QAbstractButton * b, bool on ) {
138  // work around Qt bug (tested: 4.1.4, 4.2.3, 4.3.4)
139  const bool autoExclusive = b->autoExclusive();
140  b->setAutoExclusive( false );
141  b->setChecked( b->isEnabled() && on );
142  b->setAutoExclusive( autoExclusive );
143 }
144 
145 static void set_keysize( QComboBox * cb, unsigned int strength ) {
146  if ( !cb )
147  return;
148  const int idx = cb->findData( static_cast<int>( strength ) );
149  if ( idx < 0 )
150  kWarning() << "keysize " << strength << " not allowed";
151  cb->setCurrentIndex( idx );
152 }
153 
154 static unsigned int get_keysize( const QComboBox * cb ) {
155  if ( !cb )
156  return 0;
157  const int idx = cb->currentIndex();
158  if ( idx < 0 )
159  return 0;
160  return cb->itemData( idx ).toInt();
161 }
162 
163 namespace Kleo {
164 namespace NewCertificateUi {
165  class WizardPage : public QWizardPage {
166  Q_OBJECT
167  protected:
168  explicit WizardPage( QWidget * parent=0 )
169  : QWizardPage( parent ) {}
170 
171  NewCertificateWizard * wizard() const {
172  assert( static_cast<NewCertificateWizard*>( QWizardPage::wizard() ) == qobject_cast<NewCertificateWizard*>( QWizardPage::wizard() ) );
173  return static_cast<NewCertificateWizard*>( QWizardPage::wizard() );
174  }
175 
176  QAbstractButton * button( QWizard::WizardButton button ) const {
177  return QWizardPage::wizard() ? QWizardPage::wizard()->button( button ) : 0 ;
178  }
179 
180  bool isButtonVisible( QWizard::WizardButton button ) const {
181  if ( const QAbstractButton * const b = this->button( button ) )
182  return b->isVisible();
183  else
184  return false;
185  }
186 
187  QDir tmpDir() const;
188 
189  protected Q_SLOTS:
190  void setButtonVisible( QWizard::WizardButton button, bool visible ) {
191  if ( QAbstractButton * const b = this->button( button ) )
192  b->setVisible( visible );
193  }
194 
195  protected:
196 #define FIELD(type, name) type name() const { return field( QLatin1String(#name) ).value<type>(); }
197  FIELD( bool, pgp )
198  FIELD( bool, signingAllowed )
199  FIELD( bool, encryptionAllowed )
200  FIELD( bool, certificationAllowed )
201  FIELD( bool, authenticationAllowed )
202 
203  FIELD( QString, name )
204  FIELD( QString, email )
205  FIELD( QString, comment )
206  FIELD( QString, dn )
207 
208  FIELD( int, keyType )
209  FIELD( int, keyStrength )
210 
211  FIELD( int, subkeyType )
212  FIELD( int, subkeyStrength )
213 
214  FIELD( QDate, expiryDate )
215 
216  FIELD( QStringList, additionalUserIDs )
217  FIELD( QStringList, additionalEMailAddresses )
218  FIELD( QStringList, dnsNames )
219  FIELD( QStringList, uris )
220 
221  FIELD( QString, url )
222  FIELD( QString, error )
223  FIELD( QString, result )
224  FIELD( QString, fingerprint )
225 #undef FIELD
226  };
227 } // namespace NewCertificateUi
228 } // namespace Kleo
229 
230 using namespace Kleo::NewCertificateUi;
231 
232 namespace {
233 
234  class AdvancedSettingsDialog : public QDialog {
235  Q_OBJECT
236  Q_PROPERTY( QStringList additionalUserIDs READ additionalUserIDs WRITE setAdditionalUserIDs )
237  Q_PROPERTY( QStringList additionalEMailAddresses READ additionalEMailAddresses WRITE setAdditionalEMailAddresses )
238  Q_PROPERTY( QStringList dnsNames READ dnsNames WRITE setDnsNames )
239  Q_PROPERTY( QStringList uris READ uris WRITE setUris )
240  Q_PROPERTY( uint keyStrength READ keyStrength WRITE setKeyStrength )
241  Q_PROPERTY( uint keyType READ keyType WRITE setKeyType )
242  Q_PROPERTY( uint subkeyStrength READ subkeyStrength WRITE setSubkeyStrength )
243  Q_PROPERTY( uint subkeyType READ subkeyType WRITE setSubkeyType )
244  Q_PROPERTY( bool signingAllowed READ signingAllowed WRITE setSigningAllowed )
245  Q_PROPERTY( bool encryptionAllowed READ encryptionAllowed WRITE setEncryptionAllowed )
246  Q_PROPERTY( bool certificationAllowed READ certificationAllowed WRITE setCertificationAllowed )
247  Q_PROPERTY( bool authenticationAllowed READ authenticationAllowed WRITE setAuthenticationAllowed )
248  Q_PROPERTY( QDate expiryDate READ expiryDate WRITE setExpiryDate )
249  public:
250  explicit AdvancedSettingsDialog( QWidget * parent=0 )
251  : QDialog( parent ),
252  protocol( UnknownProtocol ),
253  pgpDefaultAlgorithm( GPGME_PK_ELG_E ),
254  cmsDefaultAlgorithm( GPGME_PK_RSA ),
255  keyTypeImmutable( false ),
256  ui()
257  {
258  ui.setupUi( this );
259  const QDate today = QDate::currentDate();
260  ui.expiryDE->setMinimumDate( today );
261  ui.expiryDE->setDate( today.addYears( 2 ) );
262  ui.emailLW->setDefaultValue( i18n("new email") );
263  ui.dnsLW->setDefaultValue( i18n("new dns name") );
264  ui.uriLW->setDefaultValue( i18n("new uri") );
265 
266  fillKeySizeComboBoxen();
267  }
268 
269  void setProtocol( GpgME::Protocol proto ) {
270  if ( protocol == proto )
271  return;
272  protocol = proto;
273  loadDefaultKeyType();
274  }
275 
276  void setAdditionalUserIDs( const QStringList & items ) { ui.uidLW->setItems( items ); }
277  QStringList additionalUserIDs() const { return ui.uidLW->items(); }
278 
279  void setAdditionalEMailAddresses( const QStringList & items ) { ui.emailLW->setItems( items ); }
280  QStringList additionalEMailAddresses() const { return ui.emailLW->items(); }
281 
282  void setDnsNames( const QStringList & items ) { ui.dnsLW->setItems( items ); }
283  QStringList dnsNames() const { return ui.dnsLW->items(); }
284 
285  void setUris( const QStringList & items ) { ui.uriLW->setItems( items ); }
286  QStringList uris() const { return ui.uriLW->items(); }
287 
288 
289  void setKeyStrength( unsigned int strength ) {
290  set_keysize( ui.rsaKeyStrengthCB, strength );
291  set_keysize( ui.dsaKeyStrengthCB, strength );
292  }
293  unsigned int keyStrength() const {
294  return
295  ui.dsaRB->isChecked() ? get_keysize( ui.dsaKeyStrengthCB ) :
296  ui.rsaRB->isChecked() ? get_keysize( ui.rsaKeyStrengthCB ) : 0 ;
297  }
298 
299  void setKeyType( unsigned int algo ) {
300  QRadioButton * const rb =
301  is_rsa( algo ) ? ui.rsaRB :
302  is_dsa( algo ) ? ui.dsaRB : 0 ;
303  if ( rb )
304  rb->setChecked( true );
305  }
306  unsigned int keyType() const {
307  return
308  ui.dsaRB->isChecked() ? GPGME_PK_DSA :
309  ui.rsaRB->isChecked() ? GPGME_PK_RSA :
310  0 ;
311  }
312 
313  void setSubkeyType( unsigned int algo ) { ui.elgCB->setChecked( is_elg( algo ) ); }
314  unsigned int subkeyType() const { return ui.elgCB->isChecked() ? GPGME_PK_ELG_E : 0 ; }
315 
316  void setSubkeyStrength( unsigned int strength ) {
317  set_keysize( ui.elgKeyStrengthCB, strength );
318  }
319  unsigned int subkeyStrength() const {
320  return get_keysize( ui.elgKeyStrengthCB );
321  }
322 
323  void setSigningAllowed( bool on ) { ui.signingCB->setChecked( on ); }
324  bool signingAllowed() const { return ui.signingCB->isChecked(); }
325 
326  void setEncryptionAllowed( bool on ) { ui.encryptionCB->setChecked( on ); }
327  bool encryptionAllowed() const { return ui.encryptionCB->isChecked(); }
328 
329  void setCertificationAllowed( bool on ) { ui.certificationCB->setChecked( on ); }
330  bool certificationAllowed() const { return ui.certificationCB->isChecked(); }
331 
332  void setAuthenticationAllowed( bool on ) { ui.authenticationCB->setChecked( on ); }
333  bool authenticationAllowed() const { return ui.authenticationCB->isChecked(); }
334 
335  void setExpiryDate( const QDate & date ) { if ( date.isValid() ) ui.expiryDE->setDate( date ); else ui.expiryCB->setChecked( false ); }
336  QDate expiryDate() const { return ui.expiryCB->isChecked() ? ui.expiryDE->date() : QDate() ; }
337 
338  Q_SIGNALS:
339  void changed();
340 
341  private Q_SLOTS:
342  void slotKeyMaterialSelectionChanged() {
343  const unsigned int algo = keyType();
344  const unsigned int sk_algo = subkeyType();
345  if ( protocol == OpenPGP ) {
346  if ( !keyTypeImmutable ) {
347  ui.elgCB->setEnabled( is_dsa( algo ) );
348  if ( sender() == ui.dsaRB || sender() == ui.rsaRB )
349  ui.elgCB->setChecked( is_dsa( algo ) );
350  }
351  if ( is_rsa( algo ) ) {
352  ui.encryptionCB->setEnabled( true );
353  ui.encryptionCB->setChecked( true );
354  ui.signingCB->setEnabled( true );
355  ui.signingCB->setChecked( true );
356  ui.authenticationCB->setEnabled( true );
357  } else if ( is_dsa( algo ) ) {
358  ui.encryptionCB->setEnabled( false );
359  if ( is_elg( sk_algo ) )
360  ui.encryptionCB->setChecked( true );
361  else
362  ui.encryptionCB->setChecked( false );
363  }
364  } else {
365  //assert( is_rsa( keyType() ) ); // it can happen through misconfiguration by the admin that no key type is selectable at all
366  }
367  }
368 
369  void slotSigningAllowedToggled( bool on ) {
370  if ( !on && protocol == CMS && !encryptionAllowed() )
371  setEncryptionAllowed( true );
372  }
373  void slotEncryptionAllowedToggled( bool on ) {
374  if ( !on && protocol == CMS && !signingAllowed() )
375  setSigningAllowed( true );
376  }
377 
378  private:
379  void fillKeySizeComboBoxen();
380  void loadDefaultKeyType();
381  void updateWidgetVisibility();
382 
383  private:
384  GpgME::Protocol protocol;
385  unsigned int pgpDefaultAlgorithm;
386  unsigned int cmsDefaultAlgorithm;
387  bool keyTypeImmutable;
388  Ui_AdvancedSettingsDialog ui;
389  };
390 
391  class ChooseProtocolPage : public WizardPage {
392  Q_OBJECT
393  public:
394  explicit ChooseProtocolPage( QWidget * p=0 )
395  : WizardPage( p ),
396  initialized( false ),
397  ui()
398  {
399  ui.setupUi( this );
400  registerField( QLatin1String("pgp"), ui.pgpCLB );
401  }
402 
403  void setProtocol( Protocol proto ) {
404  if ( proto == OpenPGP )
405  ui.pgpCLB->setChecked( true );
406  else if ( proto == CMS )
407  ui.x509CLB->setChecked( true );
408  else {
409  force_set_checked( ui.pgpCLB, false );
410  force_set_checked( ui.x509CLB, false );
411  }
412  }
413 
414  Protocol protocol() const {
415  return
416  ui.pgpCLB->isChecked() ? OpenPGP :
417  ui.x509CLB->isChecked() ? CMS : UnknownProtocol ;
418  }
419 
420  /* reimp */ void initializePage() {
421  if ( !initialized ) {
422  connect( ui.pgpCLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
423  connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
424  }
425  initialized = true;
426  }
427 
428  /* reimp */ bool isComplete() const {
429  return protocol() != UnknownProtocol ;
430  }
431 
432  private:
433  bool initialized : 1;
434  Ui_ChooseProtocolPage ui;
435  };
436 
437  struct Line {
438  QString attr;
439  QString label;
440  QString regex;
441  QLineEdit * edit;
442  };
443 
444  class EnterDetailsPage : public WizardPage {
445  Q_OBJECT
446  public:
447  explicit EnterDetailsPage( QWidget * p=0 )
448  : WizardPage( p ), dialog( this ), ui()
449  {
450  ui.setupUi( this );
451 
452  // set errorLB to have a fixed height of two lines:
453  ui.errorLB->setText( QLatin1String("2<br>1") );
454  ui.errorLB->setFixedHeight( ui.errorLB->minimumSizeHint().height() );
455  ui.errorLB->clear();
456 
457  connect( ui.resultLE, SIGNAL(textChanged(QString)),
458  SIGNAL(completeChanged()) );
459  // The email doesn't necessarily show up in ui.resultLE:
460  connect( ui.emailLE, SIGNAL(textChanged(QString)),
461  SIGNAL(completeChanged()) );
462  connect( ui.addEmailToDnCB, SIGNAL(toggled(bool)),
463  SLOT(slotUpdateResultLabel()) );
464  registerDialogPropertiesAsFields();
465  registerField( QLatin1String("dn"), ui.resultLE );
466  registerField( QLatin1String("name"), ui.nameLE );
467  registerField( QLatin1String("email"), ui.emailLE );
468  registerField( QLatin1String("comment"), ui.commentLE );
469  updateForm();
470  }
471 
472  /* reimp */ bool isComplete() const;
473  /* reimp */ void initializePage() {
474  updateForm();
475  dialog.setProtocol( pgp() ? OpenPGP : CMS );
476  }
477  /* reimp */ void cleanupPage() {
478  saveValues();
479  }
480 
481  private:
482  void updateForm();
483  void clearForm();
484  void saveValues();
485  void registerDialogPropertiesAsFields();
486 
487  private:
488  QString pgpUserID() const;
489  QString cmsDN() const;
490 
491  private Q_SLOTS:
492  void slotAdvancedSettingsClicked();
493  void slotUpdateResultLabel() {
494  ui.resultLE->setText( pgp() ? pgpUserID() : cmsDN() );
495  }
496 
497  private:
498  QVector<Line> lineList;
499  QList<QWidget*> dynamicWidgets;
500  QMap<QString,QString> savedValues;
501  AdvancedSettingsDialog dialog;
502  Ui_EnterDetailsPage ui;
503  };
504 
505  class OverviewPage : public WizardPage {
506  Q_OBJECT
507  public:
508  explicit OverviewPage( QWidget * p=0 )
509  : WizardPage( p ), ui()
510  {
511  ui.setupUi( this );
512  setCommitPage( true );
513  setButtonText( QWizard::CommitButton, i18nc("@action", "Create Key") );
514  }
515 
516  /* reimp */ void initializePage() {
517  slotShowDetails();
518  }
519 
520  private Q_SLOTS:
521  void slotShowDetails() {
522  ui.textBrowser->setHtml( i18nFormatGnupgKeyParms( ui.showAllDetailsCB->isChecked() ) );
523  }
524 
525  private:
526  QStringList i18nKeyUsages() const;
527  QStringList i18nSubkeyUsages() const;
528  QStringList i18nCombinedKeyUsages() const;
529  QString i18nFormatGnupgKeyParms( bool details ) const;
530 
531  private:
532  Ui_OverviewPage ui;
533  };
534 
535  class KeyCreationPage : public WizardPage {
536  Q_OBJECT
537  public:
538  explicit KeyCreationPage( QWidget * p=0 )
539  : WizardPage( p ),
540  ui()
541  {
542  ui.setupUi( this );
543  }
544 
545  /* reimp */ bool isComplete() const {
546  return !job;
547  }
548 
549  /* reimp */ void initializePage() {
550  startJob();
551  }
552 
553  private:
554  void startJob() {
555  const CryptoBackend::Protocol * const proto = CryptoBackendFactory::instance()->protocol( pgp() ? OpenPGP : CMS );
556  if ( !proto )
557  return;
558  KeyGenerationJob * const j = proto->keyGenerationJob();
559  if ( !j )
560  return;
561  connect( j, SIGNAL(result(GpgME::KeyGenerationResult,QByteArray,QString)),
562  this, SLOT(slotResult(GpgME::KeyGenerationResult,QByteArray,QString)) );
563  if ( const Error err = j->start( createGnupgKeyParms() ) )
564  setField( QLatin1String("error"), i18n("Could not start certificate creation: %1",
565  QString::fromLocal8Bit( err.asString() ) ) );
566  else
567  job = j;
568  }
569  QStringList keyUsages() const;
570  QStringList subkeyUsages() const;
571  QString createGnupgKeyParms() const;
572 
573  private Q_SLOTS:
574  void slotResult( const GpgME::KeyGenerationResult & result, const QByteArray & request, const QString & auditLog )
575  {
576  Q_UNUSED( auditLog );
577  if ( result.error().code() ) {
578  setField( QLatin1String("error"), result.error().isCanceled()
579  ? i18n("Operation canceled.")
580  : i18n("Could not create certificate: %1",
581  QString::fromLocal8Bit( result.error().asString() ) ) );
582  setField( QLatin1String("url"), QString() );
583  setField( QLatin1String("result"), QString() );
584  } else if ( pgp() ) {
585  setField( QLatin1String("error"), QString() );
586  setField( QLatin1String("url"), QString() );
587  setField( QLatin1String("result"), i18n("Certificate created successfully.\n"
588  "Fingerprint: %1", QLatin1String(result.fingerprint()) ) );
589  } else {
590  QFile file( tmpDir().absoluteFilePath( QLatin1String("request.p10") ) );
591 
592  if ( !file.open( QIODevice::WriteOnly ) ) {
593  setField( QLatin1String("error"), i18n("Could not write output file %1: %2",
594  file.fileName(), file.errorString() ) );
595  setField( QLatin1String("url"), QString() );
596  setField( QLatin1String("result"), QString() );
597  } else {
598  file.write( request );
599  setField( QLatin1String("error"), QString() );
600  setField( QLatin1String("url"), QUrl::fromLocalFile( file.fileName() ).toString() );
601  setField( QLatin1String("result"), i18n("Certificate created successfully.") );
602  }
603  }
604  setField( QLatin1String("fingerprint"), QString::fromLatin1( result.fingerprint() ) );
605  job = 0;
606  emit completeChanged();
607  QMetaObject::invokeMethod( wizard(), "next", Qt::QueuedConnection );
608  }
609 
610  private:
611  QPointer<KeyGenerationJob> job;
612  Ui_KeyCreationPage ui;
613  };
614 
615  class ResultPage : public WizardPage {
616  Q_OBJECT
617  public:
618  explicit ResultPage( QWidget * p=0 )
619  : WizardPage( p ),
620  initialized( false ),
621  successfullyCreatedSigningCertificate( false ),
622  successfullyCreatedEncryptionCertificate( false ),
623  ui()
624  {
625  ui.setupUi( this );
626  ui.dragQueen->setPixmap( KIcon( QLatin1String("kleopatra") ).pixmap( 64, 64 ) );
627  registerField( QLatin1String("error"), ui.errorTB, "plainText" );
628  registerField( QLatin1String("result"), ui.resultTB, "plainText" );
629  registerField( QLatin1String("url"), ui.dragQueen, "url" );
630  // hidden field, since QWizard can't deal with non-widget-backed fields...
631  QLineEdit * le = new QLineEdit( this );
632  le->hide();
633  registerField( QLatin1String("fingerprint"), le );
634  }
635 
636  /* reimp */ void initializePage() {
637  const bool error = isError();
638 
639  if ( error ) {
640  setTitle( i18nc("@title","Key Creation Failed") );
641  setSubTitle( i18n("Key pair creation failed. Please find details about the failure below.") );
642  } else {
643  setTitle( i18nc("@title","Key Pair Successfully Created") );
644  setSubTitle( i18n("Your new key pair was created successfully. Please find details on the result and some suggested next steps below.") );
645  }
646 
647  ui.resultTB ->setVisible( !error );
648  ui.errorTB ->setVisible( error );
649  ui.dragQueen ->setVisible( !error && !pgp() );
650  ui.restartWizardPB ->setVisible( error );
651  ui.nextStepsGB ->setVisible( !error );
652  ui.saveRequestToFilePB ->setVisible( !pgp() );
653  ui.makeBackupPB ->setVisible( pgp() );
654  ui.createRevocationRequestPB->setVisible( pgp() && false ); // not implemented
655 
656 #ifdef KDEPIM_MOBILE_UI
657  ui.sendCertificateByEMailPB ->setVisible( false );
658  ui.sendRequestByEMailPB ->setVisible( false );
659  ui.uploadToKeyserverPB ->setVisible( false );
660 #else
661  ui.sendCertificateByEMailPB ->setVisible( pgp() );
662  ui.sendRequestByEMailPB ->setVisible( !pgp() );
663  ui.uploadToKeyserverPB ->setVisible( pgp() );
664 #endif
665 
666  if ( !error && !pgp() ) {
667  if ( signingAllowed() && !encryptionAllowed() )
668  successfullyCreatedSigningCertificate = true;
669  else if ( !signingAllowed() && encryptionAllowed() )
670  successfullyCreatedEncryptionCertificate = true;
671  else
672  successfullyCreatedEncryptionCertificate = successfullyCreatedSigningCertificate = true;
673  }
674 
675  ui.createSigningCertificatePB->setVisible( successfullyCreatedEncryptionCertificate && !successfullyCreatedSigningCertificate );
676  ui.createEncryptionCertificatePB->setVisible( successfullyCreatedSigningCertificate && !successfullyCreatedEncryptionCertificate );
677 
678  setButtonVisible( QWizard::CancelButton, error );
679 
680  if ( !initialized )
681  connect( ui.restartWizardPB, SIGNAL(clicked()),
682  wizard(), SLOT(restart()) );
683  initialized = true;
684  }
685 
686  /* reimp */ void cleanupPage() {
687  setButtonVisible( QWizard::CancelButton, true );
688  }
689 
690  bool isError() const {
691  return !ui.errorTB->toPlainText().isEmpty();
692  }
693 
694  /* reimp */ bool isComplete() const {
695  return !isError();
696  }
697 
698  private:
699  Key key() const {
700  return KeyCache::instance()->findByFingerprint( fingerprint().toLatin1().constData() );
701  }
702 
703  private Q_SLOTS:
704  void slotSaveRequestToFile() {
705  QString fileName = FileDialog::getSaveFileName( this, i18nc("@title", "Save Request"),
706  QLatin1String("imp"), i18n("PKCS#10 Requests (*.p10)") );
707  if ( fileName.isEmpty() )
708  return;
709  if ( !fileName.endsWith( QLatin1String( ".p10" ), Qt::CaseInsensitive ) )
710  fileName += QLatin1String(".p10");
711  QFile src( QUrl( url() ).toLocalFile() );
712  if ( !src.copy( fileName ) )
713  KMessageBox::error( this,
714  i18nc("@info",
715  "Could not copy temporary file <filename>%1</filename> "
716  "to file <filename>%2</filename>: <message>%3</message>",
717  src.fileName(), fileName, src.errorString() ),
718  i18nc("@title", "Error Saving Request") );
719  else
720  KMessageBox::information( this,
721  i18nc("@info",
722  "<para>Successfully wrote request to <filename>%1</filename>.</para>"
723  "<para>You should now send the request to the Certification Authority (CA).</para>",
724  fileName ),
725  i18nc("@title", "Request Saved" ) );
726  }
727 
728  void slotSendRequestByEMail() {
729  if ( pgp() )
730  return;
731  const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );
732  invokeMailer( config.readEntry( "CAEmailAddress" ), // to
733  i18n("Please process this certificate."), // subject
734  i18n("Please process this certificate and inform the sender about the location to fetch the resulting certificate.\n\nThanks,\n"), // body
735  QUrl( url() ).toLocalFile() ); // attachment
736  }
737 
738  void slotSendCertificateByEMail() {
739  if ( !pgp() || exportCertificateCommand )
740  return;
741  ExportCertificateCommand * cmd = new ExportCertificateCommand( key() );
742  connect( cmd, SIGNAL(finished()), SLOT(slotSendCertificateByEMailContinuation()) );
743  cmd->setOpenPGPFileName( tmpDir().absoluteFilePath( fingerprint() + QLatin1String(".asc") ) );
744  cmd->start();
745  exportCertificateCommand = cmd;
746  }
747 
748  void slotSendCertificateByEMailContinuation() {
749  if ( !exportCertificateCommand )
750  return;
751  // ### better error handling?
752  const QString fileName = exportCertificateCommand->openPGPFileName();
753  kDebug() << "fileName" << fileName;
754  exportCertificateCommand = 0;
755  if ( fileName.isEmpty() )
756  return;
757  invokeMailer( QString(), // to
758  i18n("My new OpenPGP certificate"), // subject
759  i18n("Please find attached my new OpenPGP certificate."), // body
760  fileName );
761  }
762 
763  QByteArray ol_quote( QByteArray str ) {
764 #ifdef Q_OS_WIN
765  return "\"\"" + str.replace( '"', "\\\"" ) + "\"\"";
766  //return '"' + str.replace( '"', "\\\"" ) + '"';
767 #else
768  return str;
769 #endif
770  }
771 
772  void invokeMailer( const QString & to, const QString & subject, QString body, const QString & attachment ) {
773  kDebug() << "to:" << to << "subject:" << subject
774  << "body:" << body << "attachment:" << attachment;
775  // KToolInvocation::invokeMailer is broken on Windows, and openUrl works fine on Unix, too.
776 
777  // RFC 2368 says body's linebreaks need to be encoded as
778  // "%0D%0A", so normalize body to CRLF:
779  body.replace( QLatin1Char( '\n' ), QLatin1String( "\r\n" ) ).remove( QLatin1String( "\r\r" ) );
780 
781  QByteArray encoded = "mailto:?to=" + QUrl::toPercentEncoding( to )
782  + "&subject=" + QUrl::toPercentEncoding( subject )
783  + "&body=" + QUrl::toPercentEncoding( body ) ;
784  if ( !attachment.isEmpty() )
785  encoded += "&attach=" + ol_quote( QUrl::toPercentEncoding( QFileInfo( attachment ).absoluteFilePath() ) );
786  kDebug() << "openUrl" << QUrl::fromEncoded( encoded );
787  QDesktopServices::openUrl( QUrl::fromEncoded( encoded ) );
788  KMessageBox::information( this,
789  i18nc("@info",
790  "<para><application>Kleopatra</application> tried to send a mail via your default mail client.</para>"
791  "<para>Some mail clients are known not to support attachments when invoked this way.</para>"
792  "<para>If your mail client does not have an attachment, then drag the <application>Kleopatra</application> icon and drop it on the message compose window of your mail client.</para>"
793  "<para>If that does not work, either, save the request to a file, and then attach that.</para>"),
794  i18nc("@title", "Sending Mail"),
795  QLatin1String("newcertificatewizard-mailto-troubles") );
796  }
797 
798  void slotUploadCertificateToDirectoryServer() {
799  if ( pgp() )
800  ( new ExportOpenPGPCertsToServerCommand( key() ) )->start();
801  }
802 
803  void slotBackupCertificate() {
804  if ( pgp() )
805  ( new ExportSecretKeyCommand( key() ) )->start();
806  }
807 
808  void slotCreateRevocationRequest() {
809 
810  }
811 
812  void slotCreateSigningCertificate() {
813  if ( successfullyCreatedSigningCertificate )
814  return;
815  toggleSignEncryptAndRestart();
816  }
817 
818  void slotCreateEncryptionCertificate() {
819  if ( successfullyCreatedEncryptionCertificate )
820  return;
821  toggleSignEncryptAndRestart();
822  }
823 
824  private:
825  void toggleSignEncryptAndRestart() {
826  if ( !wizard() )
827  return;
828  if ( KMessageBox::warningContinueCancel(
829  this,
830  i18nc("@info",
831  "This operation will delete the certification request. "
832  "Please make sure that you have sent or saved it before proceeding." ),
833  i18nc("@title", "Certification Request About To Be Deleted") ) != KMessageBox::Continue )
834  return;
835  const bool sign = signingAllowed();
836  const bool encr = encryptionAllowed();
837  setField( QLatin1String("signingAllowed"), !sign );
838  setField( QLatin1String("encryptionAllowed"), !encr );
839  // restart and skip to Overview Page:
840  wizard()->restart();
841  for ( int i = wizard()->currentId() ; i < NewCertificateWizard::OverviewPageId ; ++i )
842  wizard()->next();
843  }
844 
845  private:
846  bool initialized : 1;
847  bool successfullyCreatedSigningCertificate : 1;
848  bool successfullyCreatedEncryptionCertificate : 1;
849  QPointer<ExportCertificateCommand> exportCertificateCommand;
850  Ui_ResultPage ui;
851  };
852 }
853 
854 class NewCertificateWizard::Private {
855  friend class ::Kleo::NewCertificateWizard;
856  friend class ::Kleo::NewCertificateUi::WizardPage;
857  NewCertificateWizard * const q;
858 public:
859  explicit Private( NewCertificateWizard * qq )
860  : q( qq ),
861  tmp( QDir::temp().absoluteFilePath( QLatin1String("kleo-") ) ),
862  ui( q )
863  {
864  q->setWindowTitle( i18nc("@title", "Certificate Creation Wizard") );
865  }
866 
867 private:
868  KTempDir tmp;
869  struct Ui {
870  ChooseProtocolPage chooseProtocolPage;
871  EnterDetailsPage enterDetailsPage;
872  OverviewPage overviewPage;
873  KeyCreationPage keyCreationPage;
874  ResultPage resultPage;
875 
876  explicit Ui( NewCertificateWizard * q )
877  : chooseProtocolPage( q ),
878  enterDetailsPage( q ),
879  overviewPage( q ),
880  keyCreationPage( q ),
881  resultPage( q )
882  {
883  KDAB_SET_OBJECT_NAME( chooseProtocolPage );
884  KDAB_SET_OBJECT_NAME( enterDetailsPage );
885  KDAB_SET_OBJECT_NAME( overviewPage );
886  KDAB_SET_OBJECT_NAME( keyCreationPage );
887  KDAB_SET_OBJECT_NAME( resultPage );
888 
889  q->setOptions( DisabledBackButtonOnLastPage );
890 
891  q->setPage( ChooseProtocolPageId, &chooseProtocolPage );
892  q->setPage( EnterDetailsPageId, &enterDetailsPage );
893  q->setPage( OverviewPageId, &overviewPage );
894  q->setPage( KeyCreationPageId, &keyCreationPage );
895  q->setPage( ResultPageId, &resultPage );
896 
897  q->setStartId( ChooseProtocolPageId );
898  }
899 
900  } ui;
901 
902 };
903 
904 NewCertificateWizard::NewCertificateWizard( QWidget * p )
905  : QWizard( p ), d( new Private( this ) )
906 {
907 
908 }
909 
910 NewCertificateWizard::~NewCertificateWizard() {}
911 
912 void NewCertificateWizard::setProtocol( Protocol proto ) {
913  d->ui.chooseProtocolPage.setProtocol( proto );
914  setStartId( proto == UnknownProtocol ? ChooseProtocolPageId : EnterDetailsPageId );
915 }
916 
917 Protocol NewCertificateWizard::protocol() const {
918  return d->ui.chooseProtocolPage.protocol();
919 }
920 
921 static QString pgpLabel( const QString & attr ) {
922  if ( attr == QLatin1String("NAME") )
923  return i18n("Name");
924  if ( attr == QLatin1String("COMMENT") )
925  return i18n("Comment");
926  if ( attr == QLatin1String("EMAIL") )
927  return i18n("EMail");
928  return QString();
929 }
930 
931 static QString attributeLabel( const QString & attr, bool pgp ) {
932  if ( attr.isEmpty() )
933  return QString();
934  const QString label = pgp ? pgpLabel( attr ) : Kleo::DNAttributeMapper::instance()->name2label( attr ) ;
935  if ( !label.isEmpty() )
936  if ( pgp )
937  return label;
938  else
939  return i18nc("Format string for the labels in the \"Your Personal Data\" page",
940  "%1 (%2)", label, attr );
941  else
942  return attr;
943 }
944 
945 #if 0
946 //Not used anywhere
947 static QString attributeLabelWithColor( const QString & attr, bool pgp ) {
948  const QString result = attributeLabel( attr, pgp );
949  if ( result.isEmpty() )
950  return QString();
951  else
952  return result + ':';
953 }
954 #endif
955 
956 static QString attributeFromKey( QString key ) {
957  return key.remove( QLatin1Char('!') );
958 }
959 
960 static const char * oidForAttributeName( const QString & attr ) {
961  QByteArray attrUtf8 = attr.toUtf8();
962  for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
963  if ( qstricmp( attrUtf8, oidmap[i].name ) == 0 )
964  return oidmap[i].oid;
965  return 0;
966 }
967 
968 QDir WizardPage::tmpDir() const {
969  return wizard() ? QDir( wizard()->d->tmp.name() ) : QDir::home() ;
970 }
971 
972 void EnterDetailsPage::registerDialogPropertiesAsFields() {
973 
974  const QMetaObject * const mo = dialog.metaObject();
975  for ( unsigned int i = mo->propertyOffset(), end = i + mo->propertyCount() ; i != end ; ++i ) {
976  const QMetaProperty mp = mo->property( i );
977  if ( mp.isValid() )
978  registerField( QLatin1String(mp.name()), &dialog, mp.name(), SIGNAL(accepted()) );
979  }
980 
981 }
982 
983 void EnterDetailsPage::saveValues() {
984  Q_FOREACH( const Line & line, lineList )
985  savedValues[ attributeFromKey( line.attr ) ] = line.edit->text().trimmed();
986 }
987 
988 void EnterDetailsPage::clearForm() {
989  qDeleteAll( dynamicWidgets );
990  dynamicWidgets.clear();
991  lineList.clear();
992 
993  ui.nameLE->hide();
994  ui.nameLE->clear();
995  ui.nameLB->hide();
996  ui.nameRequiredLB->hide();
997 
998  ui.emailLE->hide();
999  ui.emailLE->clear();
1000  ui.emailLB->hide();
1001  ui.emailRequiredLB->hide();
1002 
1003  ui.commentLE->hide();
1004  ui.commentLE->clear();
1005  ui.commentLB->hide();
1006  ui.commentRequiredLB->hide();
1007 
1008  ui.addEmailToDnCB->hide();
1009 }
1010 
1011 static int row_index_of( QWidget * w, QGridLayout * l ) {
1012  const int idx = l->indexOf( w );
1013  int r, c, rs, cs;
1014  l->getItemPosition( idx, &r, &c, &rs, &cs );
1015  return r;
1016 }
1017 
1018 static QLineEdit * adjust_row( QGridLayout * l, int row, const QString & label, const QString & preset, QValidator * validator, bool readonly, bool required ) {
1019  assert( l );
1020  assert( row >= 0 );
1021  assert( row < l->rowCount() );
1022 
1023  QLabel * lb = qobject_cast<QLabel*>( l->itemAtPosition( row, 0 )->widget() );
1024  assert( lb );
1025  QLineEdit * le = qobject_cast<QLineEdit*>( l->itemAtPosition( row, 1 )->widget() );
1026  assert( le );
1027  QLabel * reqLB = qobject_cast<QLabel*>( l->itemAtPosition( row, 2 )->widget() );
1028  assert( reqLB );
1029 
1030  lb->setText( i18nc("interpunctation for labels", "%1:", label ) );
1031  le->setText( preset );
1032  reqLB->setText( required ? i18n("(required)") : i18n("(optional)") );
1033  delete le->validator();
1034  if ( validator ) {
1035  if ( !validator->parent() )
1036  validator->setParent( le );
1037  le->setValidator( validator );
1038  }
1039 
1040  le->setReadOnly( readonly && le->hasAcceptableInput() );
1041 
1042  lb->show();
1043  le->show();
1044  reqLB->show();
1045 
1046  return le;
1047 }
1048 
1049 static int add_row( QGridLayout * l, QList<QWidget*> * wl ) {
1050  assert( l );
1051  assert( wl );
1052  const int row = l->rowCount();
1053  QWidget *w1, *w2, *w3;
1054  l->addWidget( w1 = new QLabel( l->parentWidget() ), row, 0 );
1055  l->addWidget( w2 = new QLineEdit( l->parentWidget() ), row, 1 );
1056  l->addWidget( w3 = new QLabel( l->parentWidget() ), row, 2 );
1057  wl->push_back( w1 );
1058  wl->push_back( w2 );
1059  wl->push_back( w3 );
1060  return row;
1061 }
1062 
1063 void EnterDetailsPage::updateForm() {
1064 
1065  clearForm();
1066 
1067  const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );
1068 
1069  QStringList attrOrder = config.readEntry( pgp() ? "OpenPGPAttributeOrder" : "DNAttributeOrder", QStringList() );
1070  if ( attrOrder.empty() ) {
1071  if ( pgp() )
1072  attrOrder << QLatin1String("NAME!") << QLatin1String("EMAIL!") << QLatin1String("COMMENT");
1073  else
1074  attrOrder << QLatin1String("CN!") << QLatin1String("L") << QLatin1String("OU") << QLatin1String("O!") << QLatin1String("C!") << QLatin1String("EMAIL!");
1075  }
1076 
1077  QList<QWidget*> widgets;
1078  widgets.push_back( ui.nameLE );
1079  widgets.push_back( ui.emailLE );
1080  widgets.push_back( ui.commentLE );
1081 
1082  QMap<int,Line> lines;
1083 
1084  Q_FOREACH( const QString & rawKey, attrOrder ) {
1085  const QString key = rawKey.trimmed().toUpper();
1086  const QString attr = attributeFromKey( key );
1087  if ( attr.isEmpty() )
1088  continue;
1089  const QString preset = savedValues.value( attr, config.readEntry( attr, QString() ) );
1090  const bool required = key.endsWith( QLatin1Char('!') );
1091  const bool readonly = config.isEntryImmutable( attr );
1092  const QString label = config.readEntry( attr + QLatin1String("_label"),
1093  attributeLabel( attr, pgp() ) );
1094  const QString regex = config.readEntry( attr + QLatin1String("_regex") );
1095 
1096  int row;
1097  bool known = true;
1098  QValidator * validator = 0;
1099  if ( attr == QLatin1String("EMAIL") ) {
1100  row = row_index_of( ui.emailLE, ui.gridLayout );
1101  validator = regex.isEmpty() ? Validation::email() : Validation::email( QRegExp( regex ) ) ;
1102  if ( !pgp() )
1103  ui.addEmailToDnCB->show();
1104  } else if ( attr == QLatin1String("NAME") || attr == QLatin1String("CN") ) {
1105  if ( ( pgp() && attr == QLatin1String("CN") ) || ( !pgp() && attr == QLatin1String("NAME") ) )
1106  continue;
1107  if ( pgp() )
1108  validator = regex.isEmpty() ? Validation::pgpName() : Validation::pgpName( QRegExp( regex ) ) ;
1109  row = row_index_of( ui.nameLE, ui.gridLayout );
1110  } else if ( attr == QLatin1String("COMMENT") ) {
1111  if ( !pgp() )
1112  continue;
1113  validator = regex.isEmpty() ? Validation::pgpComment() : Validation::pgpComment( QRegExp( regex ) ) ;
1114  row = row_index_of( ui.commentLE, ui.gridLayout );
1115  } else {
1116  known = false;
1117  row = add_row( ui.gridLayout, &dynamicWidgets );
1118  }
1119  if ( !validator && !regex.isEmpty() )
1120  validator = new QRegExpValidator( QRegExp( regex ), 0 );
1121 
1122  QLineEdit * le = adjust_row( ui.gridLayout, row, label, preset, validator, readonly, required );
1123 
1124  const Line line = { key, label, regex, le };
1125  lines[row] = line;
1126 
1127  if ( !known )
1128  widgets.push_back( le );
1129 
1130  // don't connect twice:
1131  disconnect( le, SIGNAL(textChanged(QString)),
1132  this, SLOT(slotUpdateResultLabel()) );
1133  connect( le, SIGNAL(textChanged(QString)),
1134  this, SLOT(slotUpdateResultLabel()) );
1135  }
1136 
1137  // create lineList in visual order, so requirementsAreMet()
1138  // complains from top to bottom:
1139  lineList = kdtools::copy< QVector<Line> >( lines );
1140 
1141  widgets.push_back( ui.resultLE );
1142  widgets.push_back( ui.addEmailToDnCB );
1143  widgets.push_back( ui.advancedPB );
1144 
1145  set_tab_order( widgets );
1146 }
1147 
1148 QString EnterDetailsPage::cmsDN() const {
1149  DN dn;
1150  for ( QVector<Line>::const_iterator it = lineList.begin(), end = lineList.end() ; it != end ; ++it ) {
1151  const QString text = it->edit->text().trimmed();
1152  if ( text.isEmpty() )
1153  continue;
1154  QString attr = attributeFromKey( it->attr );
1155  if ( attr == QLatin1String("EMAIL") && !ui.addEmailToDnCB->isChecked() )
1156  continue;
1157  if ( const char * const oid = oidForAttributeName( attr ) )
1158  attr = QString::fromUtf8( oid );
1159  dn.append( DN::Attribute( attr, text ) );
1160  }
1161  return dn.dn();
1162 }
1163 
1164 QString EnterDetailsPage::pgpUserID() const {
1165  return Formatting::prettyNameAndEMail( OpenPGP, QString(),
1166  ui.nameLE->text().trimmed(),
1167  ui.emailLE->text().trimmed(),
1168  ui.commentLE->text().trimmed() );
1169 }
1170 
1171 static bool has_intermediate_input( const QLineEdit * le ) {
1172  QString text = le->text();
1173  int pos = le->cursorPosition();
1174  const QValidator * const v = le->validator();
1175  return v && v->validate( text, pos ) == QValidator::Intermediate ;
1176 }
1177 
1178 static bool requirementsAreMet( const QVector<Line> & list, QString & error ) {
1179  Q_FOREACH( const Line & line, list ) {
1180  const QLineEdit * le = line.edit;
1181  if ( !le )
1182  continue;
1183  const QString key = line.attr;
1184  kDebug() << "requirementsAreMet(): checking \"" << key << "\" against \"" << le->text() << "\":";
1185  if ( le->text().trimmed().isEmpty() ) {
1186  if ( key.endsWith(QLatin1Char('!')) ) {
1187  if ( line.regex.isEmpty() )
1188  error = i18nc("@info","<interface>%1</interface> is required, but empty.", line.label );
1189  else
1190  error = i18nc("@info","<interface>%1</interface> is required, but empty.<nl/>"
1191  "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1192  return false;
1193  }
1194  } else if ( has_intermediate_input( le ) ) {
1195  if ( line.regex.isEmpty() )
1196  error = i18nc("@info","<interface>%1</interface> is incomplete.", line.label );
1197  else
1198  error = i18nc("@info","<interface>%1</interface> is incomplete.<nl/>"
1199  "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1200  return false;
1201  } else if ( !le->hasAcceptableInput() ) {
1202  if ( line.regex.isEmpty() )
1203  error = i18nc("@info","<interface>%1</interface> is invalid.", line.label );
1204  else
1205  error = i18nc("@info","<interface>%1</interface> is invalid.<nl/>"
1206  "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1207  return false;
1208  }
1209  kDebug() << "ok" << endl;
1210  }
1211  return true;
1212 }
1213 
1214 bool EnterDetailsPage::isComplete() const {
1215  QString error;
1216  const bool ok = requirementsAreMet( lineList, error );
1217  ui.errorLB->setText( error );
1218  return ok;
1219 }
1220 
1221 void EnterDetailsPage::slotAdvancedSettingsClicked() {
1222  dialog.exec();
1223 }
1224 
1225 QStringList KeyCreationPage::keyUsages() const {
1226  QStringList usages;
1227  if ( signingAllowed() )
1228  usages << QLatin1String("sign");
1229  if ( encryptionAllowed() && !is_dsa( keyType() ) )
1230  usages << QLatin1String("encrypt");
1231  if ( 0 ) // not needed in pgp (implied) and not supported in cms
1232  if ( certificationAllowed() )
1233  usages << QLatin1String("certify");
1234  if ( authenticationAllowed() )
1235  usages << QLatin1String("auth");
1236  return usages;
1237 }
1238 
1239 QStringList OverviewPage::i18nKeyUsages() const {
1240  QStringList usages;
1241  if ( signingAllowed() )
1242  usages << i18n("Sign");
1243  if ( encryptionAllowed() && !is_dsa( keyType() ) )
1244  usages << i18n("Encrypt");
1245  if ( 0 ) // not needed in pgp (implied) and not supported in cms
1246  if ( certificationAllowed() )
1247  usages << i18n("Certify");
1248  if ( authenticationAllowed() )
1249  usages << i18n("Authenticate");
1250  return usages;
1251 }
1252 
1253 QStringList KeyCreationPage::subkeyUsages() const {
1254  QStringList usages;
1255  if ( encryptionAllowed() && is_dsa( keyType() ) ) {
1256  assert( subkeyType() );
1257  assert( is_elg( subkeyType() ) );
1258  usages << QLatin1String("encrypt");
1259  }
1260  return usages;
1261 }
1262 
1263 QStringList OverviewPage::i18nSubkeyUsages() const {
1264  QStringList usages;
1265  if ( encryptionAllowed() && is_dsa( keyType() ) ) {
1266  assert( subkeyType() );
1267  assert( is_elg( subkeyType() ) );
1268  usages << i18n("Encrypt");
1269  }
1270  return usages;
1271 }
1272 
1273 QStringList OverviewPage::i18nCombinedKeyUsages() const {
1274  return i18nSubkeyUsages() + i18nKeyUsages();
1275 }
1276 
1277 namespace {
1278  template <typename T=QString>
1279  struct Row {
1280  QString key;
1281  T value;
1282 
1283  Row( const QString & k, const T & v ) : key( k ), value( v ) {}
1284  };
1285  template <typename T>
1286  QTextStream & operator<<( QTextStream & s, const Row<T> & row ) {
1287  if ( row.key.isEmpty() )
1288  return s;
1289  else
1290  return s << "<tr><td>" << row.key << "</td><td>" << row.value << "</td></tr>";
1291  }
1292 }
1293 
1294 QString OverviewPage::i18nFormatGnupgKeyParms( bool details ) const {
1295  QString result;
1296  QTextStream s( &result );
1297  s << "<table>";
1298  if ( pgp() )
1299  s << Row< >( i18n("Name:"), name() );
1300  s << Row< >( i18n("Email Address:"), email() );
1301  if ( pgp() ) {
1302  if ( !comment().isEmpty() )
1303  s << Row< >( i18n("Comment:"), comment() );
1304  } else {
1305  s << Row< >( i18n("Subject-DN:"), DN( dn() ).dn( QLatin1String(",<br>") ) );
1306  }
1307  if ( details ) {
1308  s << Row< >( i18n("Key Type:"), QLatin1String(gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( keyType() ) )) );
1309  if ( const unsigned int strength = keyStrength() )
1310  s << Row< >( i18n("Key Strength:"), i18np("1 bit", "%1 bits", strength ) );
1311  else
1312  s << Row< >( i18n("Key Strength:"), i18n("default") );
1313  s << Row< >( i18n("Certificate Usage:"), i18nCombinedKeyUsages().join(i18nc("separator for key usages",",&nbsp;")) );
1314  if ( const unsigned int subkey = subkeyType() ) {
1315  s << Row< >( i18n("Subkey Type:"), QLatin1String(gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( subkey ) )) );
1316  if ( const unsigned int strength = subkeyStrength() )
1317  s << Row< >( i18n("Subkey Strength:"), i18np("1 bit", "%1 bits", strength ) );
1318  else
1319  s << Row< >( i18n("Subkey Strength:"), i18n("default") );
1320  s << Row< >( i18n("Subkey Usage:"), i18nSubkeyUsages().join(i18nc("separator for key usages",",&nbsp;")) );
1321  }
1322  }
1323  if ( pgp() && details && expiryDate().isValid() )
1324  s << Row< >( i18n("Valid Until:"), KGlobal::locale()->formatDate( expiryDate() ) );
1325  if ( !pgp() && details ) {
1326  Q_FOREACH( const QString & email, additionalEMailAddresses() )
1327  s << Row< >( i18n("Add. Email Address:"),email );
1328  Q_FOREACH( const QString & dns, dnsNames() )
1329  s << Row< >( i18n("DNS Name:"), dns );
1330  Q_FOREACH( const QString & uri, uris() )
1331  s << Row< >( i18n("URI:"), uri );
1332  }
1333  return result;
1334 }
1335 
1336 static QString encode_dns( const QString & dns ) {
1337  return QString::fromLatin1( QUrl::toAce( dns ) );
1338 }
1339 
1340 static QString encode_email( const QString & email ) {
1341  const int at = email.lastIndexOf( QLatin1Char('@') );
1342  if ( at < 0 )
1343  return email;
1344  return email.left( at + 1 ) + encode_dns( email.mid( at + 1 ) );
1345 }
1346 
1347 QString KeyCreationPage::createGnupgKeyParms() const {
1348  QString result;
1349  QTextStream s( &result );
1350  s << "<GnupgKeyParms format=\"internal\">" << endl;
1351  if ( pgp() )
1352  s << "%ask-passphrase" << endl;
1353  s << "key-type: " << gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( keyType() ) ) << endl;
1354  if ( const unsigned int strength = keyStrength() )
1355  s << "key-length: " << strength << endl;
1356  s << "key-usage: " << keyUsages().join(QLatin1String(" ")) << endl;
1357  if ( const unsigned int subkey = subkeyType() ) {
1358  s << "subkey-type: " << gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( subkey ) ) << endl;
1359  if ( const unsigned int strength = subkeyStrength() )
1360  s << "subkey-length: " << strength << endl;
1361  s << "subkey-usage: " << subkeyUsages().join(QLatin1String(" ")) << endl;
1362  }
1363  if ( pgp() && expiryDate().isValid() )
1364  s << "expire-date: " << expiryDate().toString( Qt::ISODate ) << endl;
1365  s << "name-email: " << encode_email( email() ) << endl;
1366  if ( pgp() ) {
1367  s << "name-real: " << name() << endl;
1368  if ( !comment().isEmpty() )
1369  s << "name-comment: " << comment() << endl;
1370  } else {
1371  s << "name-dn: " << dn() << endl;
1372  Q_FOREACH( const QString & email, additionalEMailAddresses() )
1373  s << "name-email: " << encode_email( email )<< endl;
1374  Q_FOREACH( const QString & dns, dnsNames() )
1375  s << "name-dns: " << encode_dns( dns ) << endl;
1376  Q_FOREACH( const QString & uri, uris() )
1377  s << "name-uri: " << uri << endl;
1378  }
1379  s << "</GnupgKeyParms>" << endl;
1380  kDebug() << '\n' << result;
1381  return result;
1382 }
1383 
1384 static void fill_combobox( QComboBox & cb, const QList<int> & sizes, const QStringList & labels ) {
1385  cb.clear();
1386  for ( int i = 0, end = sizes.size() ; i != end ; ++i ) {
1387  cb.addItem( i < labels.size() && !labels[i].trimmed().isEmpty()
1388  ? sizes[i] < 0
1389  ? i18ncp( "%2: some admin-supplied text, %1: key size in bits", "%2 (1 bit; default)", "%2 (%1 bits; default)", -sizes[i], labels[i].trimmed() )
1390  : i18ncp( "%2: some admin-supplied text, %1: key size in bits", "%2 (1 bit)", "%2 (%1 bits)", sizes[i], labels[i].trimmed() )
1391  : sizes[i] < 0
1392  ? i18ncp( "%1: key size in bits", "1 bit (default)", "%1 bits (default)", -sizes[i] )
1393  : i18ncp( "%1: key size in bits", "1 bit", "%1 bits", sizes[i] ),
1394  std::abs( sizes[i] ) );
1395  if ( sizes[i] < 0 )
1396  cb.setCurrentIndex( cb.count() - 1 );
1397  }
1398 }
1399 
1400 void AdvancedSettingsDialog::fillKeySizeComboBoxen() {
1401 
1402  const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );
1403 
1404  const QList<int> rsaKeySizes = config.readEntry( RSA_KEYSIZES_ENTRY, QList<int>() << 1536 << -2048 << 3072 << 4096 );
1405  const QList<int> dsaKeySizes = config.readEntry( DSA_KEYSIZES_ENTRY, QList<int>() << -2048 );
1406  const QList<int> elgKeySizes = config.readEntry( ELG_KEYSIZES_ENTRY, QList<int>() << 1536 << -2048 << 3072 << 4096 );
1407 
1408  const QStringList rsaKeySizeLabels = config.readEntry( RSA_KEYSIZE_LABELS_ENTRY, QStringList() );
1409  const QStringList dsaKeySizeLabels = config.readEntry( DSA_KEYSIZE_LABELS_ENTRY, QStringList() );
1410  const QStringList elgKeySizeLabels = config.readEntry( ELG_KEYSIZE_LABELS_ENTRY, QStringList() );
1411 
1412  fill_combobox( *ui.rsaKeyStrengthCB, rsaKeySizes, rsaKeySizeLabels );
1413  fill_combobox( *ui.dsaKeyStrengthCB, dsaKeySizes, dsaKeySizeLabels );
1414  fill_combobox( *ui.elgKeyStrengthCB, elgKeySizes, elgKeySizeLabels );
1415 
1416 }
1417 
1418 void AdvancedSettingsDialog::loadDefaultKeyType() {
1419 
1420  if ( protocol != CMS && protocol != OpenPGP )
1421  return;
1422 
1423  const KConfigGroup config( KGlobal::config(), "CertificateCreationWizard" );
1424 
1425  const QString entry = protocol == CMS ? QLatin1String(CMS_KEY_TYPE_ENTRY) : QLatin1String(PGP_KEY_TYPE_ENTRY) ;
1426  const QString keyType = config.readEntry( entry ).trimmed().toUpper();
1427 
1428  if ( protocol == OpenPGP && keyType == QLatin1String("DSA") ) {
1429  setKeyType( GPGME_PK_DSA );
1430  setSubkeyType( 0 );
1431  } else if ( protocol == OpenPGP && keyType == QLatin1String("DSA+ELG") ) {
1432  setKeyType( GPGME_PK_DSA );
1433  setSubkeyType( GPGME_PK_ELG_E );
1434  } else {
1435  if ( !keyType.isEmpty() && keyType != QLatin1String("RSA") )
1436  kWarning() << "invalid value \"" << qPrintable( keyType )
1437  << "\" for entry \"[CertificateCreationWizard]"
1438  << qPrintable( entry ) << "\"";
1439  setKeyType( GPGME_PK_RSA );
1440  setSubkeyType( 0 );
1441  }
1442 
1443  keyTypeImmutable = config.isEntryImmutable( entry );
1444  updateWidgetVisibility();
1445 }
1446 
1447 void AdvancedSettingsDialog::updateWidgetVisibility() {
1448  // Personal Details Page
1449  if ( protocol == OpenPGP ) { // ### hide until multi-uid is implemented
1450  if ( ui.tabWidget->indexOf( ui.personalTab ) != -1 )
1451  ui.tabWidget->removeTab( ui.tabWidget->indexOf( ui.personalTab ) );
1452  } else {
1453  if ( ui.tabWidget->indexOf( ui.personalTab ) == -1 )
1454  ui.tabWidget->addTab( ui.personalTab, tr2i18n( "Personal Details", 0 ) );
1455  }
1456  ui.uidGB->setVisible( protocol == OpenPGP );
1457  ui.uidGB->setEnabled( false );
1458  ui.uidGB->setToolTip( i18nc("@info:tooltip","Adding more than one User ID is not yet implemented.") );
1459  ui.emailGB->setVisible( protocol == CMS );
1460  ui.dnsGB->setVisible( protocol == CMS );
1461  ui.uriGB->setVisible( protocol == CMS );
1462  // Technical Details Page
1463  if ( keyTypeImmutable ) {
1464  ui.rsaRB->setEnabled( false );
1465  ui.dsaRB->setEnabled( false );
1466  ui.elgCB->setEnabled( false );
1467  } else {
1468  ui.rsaRB->setEnabled( true );
1469  ui.dsaRB->setEnabled( protocol == OpenPGP );
1470  ui.elgCB->setEnabled( protocol == OpenPGP );
1471  }
1472  ui.certificationCB->setVisible( protocol == OpenPGP ); // gpgsm limitation?
1473  ui.authenticationCB->setVisible( protocol == OpenPGP );
1474  if ( protocol == OpenPGP ) { // pgp keys must have certify capability
1475  ui.certificationCB->setChecked( true );
1476  ui.certificationCB->setEnabled( false );
1477  }
1478  if ( protocol == CMS ) {
1479  ui.encryptionCB->setEnabled( true );
1480  }
1481  ui.expiryDE->setVisible( protocol == OpenPGP );
1482  ui.expiryCB->setVisible( protocol == OpenPGP );
1483  slotKeyMaterialSelectionChanged();
1484 }
1485 
1486 #include "moc_newcertificatewizard.cpp"
1487 #include "newcertificatewizard.moc"
Kleo::ExportCertificateCommand::openPGPFileName
QString openPGPFileName() const
Definition: exportcertificatecommand.cpp:133
CMS_KEY_TYPE_ENTRY
static const char CMS_KEY_TYPE_ENTRY[]
Definition: newcertificatewizard.cpp:100
QWizard::WizardButton
WizardButton
Definition: qwizard.h:64
Kleo::NewCertificateWizard::~NewCertificateWizard
~NewCertificateWizard()
Definition: newcertificatewizard.cpp:910
Kleo::Validation::email
QValidator * email(QObject *parent=0)
Definition: validation.cpp:129
set_tab_order
static void set_tab_order(const QList< QWidget * > &wl)
Definition: newcertificatewizard.cpp:102
set_keysize
static void set_keysize(QComboBox *cb, unsigned int strength)
Definition: newcertificatewizard.cpp:145
QWizardPage::wizard
QWizard * wizard() const
Definition: qwizard.cpp:3915
QDialog
QWizardPage
The QWizardPage class is the base class for wizard pages.
Definition: qwizard.h:206
email
static std::string email(const UserID &uid)
Definition: keycache.cpp:593
PGP_KEY_TYPE_ENTRY
static const char PGP_KEY_TYPE_ENTRY[]
Definition: newcertificatewizard.cpp:99
validation.h
QWidget
ELG
Definition: newcertificatewizard.cpp:106
FIELD
#define FIELD(type, name)
Definition: newcertificatewizard.cpp:196
Kleo::NewCertificateWizard::ChooseProtocolPageId
Definition: newcertificatewizard.h:64
formatting.h
Kleo::Command::start
void start()
Definition: commands/command.cpp:182
RSA
Definition: newcertificatewizard.cpp:106
ResultPageId
Definition: newsignencryptfileswizard.cpp:90
DSA_KEYSIZE_LABELS_ENTRY
static const char DSA_KEYSIZE_LABELS_ENTRY[]
Definition: newcertificatewizard.cpp:96
add_row
static int add_row(QGridLayout *l, QList< QWidget * > *wl)
Definition: newcertificatewizard.cpp:1049
oidForAttributeName
static const char * oidForAttributeName(const QString &attr)
Definition: newcertificatewizard.cpp:960
row_index_of
static int row_index_of(QWidget *w, QGridLayout *l)
Definition: newcertificatewizard.cpp:1011
Kleo::Commands::ExportSecretKeyCommand
Definition: exportsecretkeycommand.h:44
Kleo::NewCertificateWizard::protocol
GpgME::Protocol protocol() const
Definition: newcertificatewizard.cpp:917
Kleo::NewCertificateWizard::NewCertificateWizard
NewCertificateWizard(QWidget *parent=0)
Definition: newcertificatewizard.cpp:904
Kleo::NewCertificateWizard::OverviewPageId
Definition: newcertificatewizard.h:66
is_elg
static bool is_elg(unsigned int algo)
Definition: newcertificatewizard.cpp:133
QWizard::button
QAbstractButton * button(WizardButton which) const
Definition: qwizard.cpp:2773
QWizard::CommitButton
Definition: qwizard.h:67
d
#define d
Definition: adduseridcommand.cpp:90
QValidator
is_dsa
static bool is_dsa(unsigned int algo)
Definition: newcertificatewizard.cpp:129
DSA
Definition: newcertificatewizard.cpp:106
Kleo::Class::OpenPGP
Definition: classify.h:49
Kleo::NewCertificateWizard::setProtocol
void setProtocol(GpgME::Protocol protocol)
Definition: newcertificatewizard.cpp:912
exportsecretkeycommand.h
requirementsAreMet
static bool requirementsAreMet(const QVector< Line > &list, QString &error)
Definition: newcertificatewizard.cpp:1178
adjust_row
static QLineEdit * adjust_row(QGridLayout *l, int row, const QString &label, const QString &preset, QValidator *validator, bool readonly, bool required)
Definition: newcertificatewizard.cpp:1018
fill_combobox
static void fill_combobox(QComboBox &cb, const QList< int > &sizes, const QStringList &labels)
Definition: newcertificatewizard.cpp:1384
Kleo::Validation::pgpComment
QValidator * pgpComment(QObject *parent=0)
Definition: validation.cpp:145
KDAB_SET_OBJECT_NAME
#define KDAB_SET_OBJECT_NAME(x)
Definition: kdtoolsglobal.h:66
ELG_KEYSIZE_LABELS_ENTRY
static const char ELG_KEYSIZE_LABELS_ENTRY[]
Definition: newcertificatewizard.cpp:97
Kleo::Class::CMS
Definition: classify.h:48
QWizard::setStartId
void setStartId(int id)
Definition: qwizard.cpp:2405
KeyAlgo
KeyAlgo
Definition: newcertificatewizard.cpp:106
get_keysize
static unsigned int get_keysize(const QComboBox *cb)
Definition: newcertificatewizard.cpp:154
DSA_KEYSIZES_ENTRY
static const char DSA_KEYSIZES_ENTRY[]
Definition: newcertificatewizard.cpp:92
Kleo::ExportCertificateCommand
Definition: exportcertificatecommand.h:39
Kleo::Formatting::prettyNameAndEMail
QString prettyNameAndEMail(int proto, const char *id, const char *name, const char *email, const char *comment)
Definition: formatting.cpp:87
exportopenpgpcertstoservercommand.h
is_algo
static bool is_algo(gpgme_pubkey_algo_t algo, KeyAlgo what)
Definition: newcertificatewizard.cpp:108
RSA_KEYSIZES_ENTRY
static const char RSA_KEYSIZES_ENTRY[]
Definition: newcertificatewizard.cpp:91
Kleo::FileDialog::getSaveFileName
QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(), const QString &dirID=QString(), const QString &filter=QString())
Definition: filedialog.cpp:126
newcertificatewizard.h
Kleo::ExportCertificateCommand::setOpenPGPFileName
void setOpenPGPFileName(const QString &fileName)
Definition: exportcertificatecommand.cpp:127
encode_dns
static QString encode_dns(const QString &dns)
Definition: newcertificatewizard.cpp:1336
QWizard::CancelButton
Definition: qwizard.h:69
QWizard::setOptions
void setOptions(WizardOptions options)
Definition: qwizard.cpp:2595
q
#define q
Definition: adduseridcommand.cpp:91
Kleo::NewCertificateWizard
Definition: newcertificatewizard.h:54
encode_email
static QString encode_email(const QString &email)
Definition: newcertificatewizard.cpp:1340
Kleo::KeyCache::instance
static boost::shared_ptr< const KeyCache > instance()
Definition: keycache.cpp:189
attributeFromKey
static QString attributeFromKey(QString key)
Definition: newcertificatewizard.cpp:956
exportcertificatecommand.h
Kleo::Validation::pgpName
QValidator * pgpName(QObject *parent=0)
Definition: validation.cpp:137
name
const char * name
Definition: uiserver/selectcertificatecommand.cpp:114
pgpLabel
static QString pgpLabel(const QString &attr)
Definition: newcertificatewizard.cpp:921
Kleo::NewCertificateWizard::EnterDetailsPageId
Definition: newcertificatewizard.h:65
has_intermediate_input
static bool has_intermediate_input(const QLineEdit *le)
Definition: newcertificatewizard.cpp:1171
is_rsa
static bool is_rsa(unsigned int algo)
Definition: newcertificatewizard.cpp:125
keycache.h
RSA_KEYSIZE_LABELS_ENTRY
static const char RSA_KEYSIZE_LABELS_ENTRY[]
Definition: newcertificatewizard.cpp:95
force_set_checked
static void force_set_checked(QAbstractButton *b, bool on)
Definition: newcertificatewizard.cpp:137
Kleo::Commands::ExportOpenPGPCertsToServerCommand
Definition: exportopenpgpcertstoservercommand.h:41
QWizard::setPage
void setPage(int id, QWizardPage *page)
Definition: qwizard.cpp:2219
QMap
Definition: signingcertificateselectiondialog.h:41
QWizard
The QWizard class provides a framework for wizards.
Definition: qwizard.h:51
QList
Definition: commands/command.h:46
attributeLabel
static QString attributeLabel(const QString &attr, bool pgp)
Definition: newcertificatewizard.cpp:931
ELG_KEYSIZES_ENTRY
static const char ELG_KEYSIZES_ENTRY[]
Definition: newcertificatewizard.cpp:93
filedialog.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:56:41 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal