diff --git a/GpgMEWorker.cpp b/GpgMEWorker.cpp index a1919ce..114ea2f 100644 --- a/GpgMEWorker.cpp +++ b/GpgMEWorker.cpp @@ -145,6 +145,34 @@ const Error GpgMEWorker::CertifyKey(const char* fprSigningKey, return e; } +const Error GpgMEWorker::RevokeKeyCertifications(const char* fprSigningKey, + const char* fprKeyToSign, + vector& userIDsToRevoke, + const string& passphrase) +{ + Error e; + Key signingKey = FindKey(fprSigningKey, e, true); + if (e.code() != 0) + return e; + e = m_ctx->addSigningKey(signingKey); // +++ + if (e.code() != 0) + return e; + Key keyToSign = FindKey(fprKeyToSign, e, false); + if (e.code() != 0) + return e; + + m_ctx->setPinentryMode(Context::PinentryMode::PinentryLoopback); + if (m_ppp == NULL) + m_ppp = new LoopbackPassphraseProvider(); + m_ppp->SetPassphrase(passphrase); + m_ctx->setPassphraseProvider(m_ppp); + + e = m_ctx->revokeSignature(keyToSign, signingKey, userIDsToRevoke); + m_ctx->clearSigningKeys(); + + return e; +} + const Error GpgMEWorker::SetSubkeyExpiryTime(const char* keyFpr, const char* subkeyFpr, const string& passphrase, diff --git a/GpgMEWorker.h b/GpgMEWorker.h index 10c8c44..024a9af 100644 --- a/GpgMEWorker.h +++ b/GpgMEWorker.h @@ -77,6 +77,19 @@ public: const char * fprKeyToSign, vector& userIDsToSign, int options, const string& passphrase); + /** + * Revoke UserID certifications. + * \n Requires GnuPG >= 2.2.24 + * @param fprSigningKey + * @param fprKeyToSign + * @param userIDsToRevoke : vector of ::UserID + * @param passphrase + * @return + */ + const Error RevokeKeyCertifications(const char * fprSigningKey, + const char * fprKeyToSign, + vector& userIDsToRevoke, + const string& passphrase); /** * Sets the expiry time of a single subkey. Requires GPGME >= 1.15.0. * \n If no subkey is found (wrong fpr), the expiry time of key is set diff --git a/KeyEdit.cpp b/KeyEdit.cpp index 0096ef1..b295b6e 100644 --- a/KeyEdit.cpp +++ b/KeyEdit.cpp @@ -153,19 +153,43 @@ void KeyEdit::CertifyKey() } const WString signingKey = m_popupUid->GetSelectedKey(); const WString keyToSign = m_popupUid->GetKeyToSign(); - int options = m_popupUid->GetCertifyOptions(); GpgMEWorker gpgWorker; - GpgME::Error e = gpgWorker.CertifyKey(signingKey.toUTF8().c_str(), - keyToSign.toUTF8().c_str(), - uidsToSign, options, - m_popupUid->GetPassphrase()); + GpgME::Error e; + if (m_popupUid->WhatToDo() == PopupCertifyUserId::CertifyUid) + { + int options = m_popupUid->GetCertifyOptions(); + e = gpgWorker.CertifyKey(signingKey.toUTF8().c_str(), + keyToSign.toUTF8().c_str(), + uidsToSign, options, + m_popupUid->GetPassphrase()); + } + else + { + vector uidsToRevoke + = m_popupUid->GetUidsToRevokeCertification(); + e = gpgWorker.RevokeKeyCertifications(signingKey.toUTF8().c_str(), + keyToSign.toUTF8().c_str(), + uidsToRevoke, + m_popupUid->GetPassphrase()); + } if (e.code() != 0) { - m_owner->m_tmwMessage->SetText(TR("CertificationFailure")); - m_popupUid->ShowPassphrase(true); - return; + if (m_popupUid->WhatToDo() == PopupCertifyUserId::CertifyUid) + { + m_owner->m_tmwMessage->SetText(e.asString()); + m_popupUid->ShowPassphrase(true); + return; + } + else { + m_owner->m_tmwMessage->SetText(e.asString()); + m_popupUid->ShowPassphrase(true); + return; + } } - m_owner->m_tmwMessage->SetText(TR("CertificationSuccess")); + if (m_popupUid->WhatToDo() == PopupCertifyUserId::CertifyUid) + m_owner->m_tmwMessage->SetText(TR("CertificationSuccess")); + else + m_owner->m_tmwMessage->SetText(TR("RevocationSuccess")); m_popupUid->ShowPassphrase(false); m_owner->DisplayUids(keyToSign); } diff --git a/PopupCertifyUserId.cpp b/PopupCertifyUserId.cpp index d942ca1..b6d0b12 100644 --- a/PopupCertifyUserId.cpp +++ b/PopupCertifyUserId.cpp @@ -12,7 +12,9 @@ #include "Tools.h" #include #include +#include #include +#include using namespace std; @@ -63,10 +65,10 @@ void PopupCertifyUserId::Create(vector& privateKeys, m_hblPreferences->addLayout(unique_ptr (m_vblEmail)); PresentEmail(); // Column 1 + m_gbOptions = new WGroupBox(TR("Options")); WVBoxLayout * vblOptions = new WVBoxLayout(); - m_hblPreferences->addLayout(unique_ptr (vblOptions)); - WText * lblOptions = new WText(TR("Options")); - vblOptions->addWidget(unique_ptr (lblOptions)); + m_gbOptions->setLayout(unique_ptr (vblOptions)); + m_hblPreferences->addWidget(unique_ptr (m_gbOptions)); m_cbOptionExportable = new WCheckBox(TR("ExportableCertification")); m_cbOptionExportable->setToolTip(TR("OneWayHint")); vblOptions->addWidget(unique_ptr (m_cbOptionExportable)); @@ -74,7 +76,7 @@ void PopupCertifyUserId::Create(vector& privateKeys, m_cbOptionNonRevocable->setToolTip(TR("OneWayHint")); vblOptions->addWidget(unique_ptr (m_cbOptionNonRevocable)); /*m_cbOptionTrust = new WCheckBox(TR("TrustCertification")); - vblOptions->addWidget(unique_ptr (m_cbOptionTrust));*/ + gbOptions->addWidget(unique_ptr (m_cbOptionTrust));*/ WHBoxLayout * hblPassphrase = new WHBoxLayout(); m_lblPassphrase = new WText(TR("Passphrase")); @@ -84,6 +86,18 @@ void PopupCertifyUserId::Create(vector& privateKeys, hblPassphrase->addWidget(unique_ptr (m_lePassphrase), 1); vblMain->addLayout(unique_ptr (hblPassphrase)); + WHBoxLayout * hblWhat = new WHBoxLayout(); + WRadioButton * rbCertifyUid = new WRadioButton(TR("CertifyUid")); + hblWhat->addWidget(unique_ptr (rbCertifyUid)); + WRadioButton * rbRevokeCertification = + new WRadioButton(TR("RevokeUidCertification")); + hblWhat->addWidget(unique_ptr (rbRevokeCertification)); + m_bgWhat = make_shared(); + m_bgWhat->addButton(rbCertifyUid, What::CertifyUid); + m_bgWhat->addButton(rbRevokeCertification, What::RevokeUidCertification); + m_bgWhat->setCheckedButton(rbCertifyUid); + vblMain->addLayout(unique_ptr (hblWhat)); + WHBoxLayout * hblButtons = new WHBoxLayout(); WPushButton * btnClose = new WPushButton(TR("Close")); hblButtons->addWidget(unique_ptr (btnClose)); @@ -99,6 +113,7 @@ void PopupCertifyUserId::Create(vector& privateKeys, m_cbOptionNonRevocable->unChecked().connect(std::bind(&PopupCertifyUserId::OnCertifyOptionUnChecked, this, 2)); // m_cbOptionTrust->unChecked().connect(std::bind(&PopupCertifyUserId::OnCertifyOptionUnChecked, this, 4)); btnClose->clicked().connect(this, &WPopupWidget::hide); + m_bgWhat->checkedChanged().connect(this, &PopupCertifyUserId::OnButtonGroupWhat); } void PopupCertifyUserId::FillPrivateKeyComboBox(vector& privateKeys) @@ -175,8 +190,8 @@ void PopupCertifyUserId::PresentEmail() WCheckBox * cbEmail = new WCheckBox(it->email()); m_vblEmail->addWidget(unique_ptr (cbEmail)); cbEmail->setId(std::to_string(id)); - cbEmail->checked().connect(std::bind(&PopupCertifyUserId::OnEmailChecked, this, cbEmail)); - cbEmail->unChecked().connect(std::bind(&PopupCertifyUserId::OnEmailUnChecked, this, cbEmail)); + cbEmail->checked().connect(std::bind(&PopupCertifyUserId::OnEmailChecked, this, cbEmail, (*it))); + cbEmail->unChecked().connect(std::bind(&PopupCertifyUserId::OnEmailUnChecked, this, cbEmail, (*it))); id++; } } @@ -220,25 +235,32 @@ void PopupCertifyUserId::ShowPassphrase(bool show) } } -void PopupCertifyUserId::OnEmailChecked(WCheckBox* cb) +void PopupCertifyUserId::OnEmailChecked(WCheckBox* cb, GpgME::UserID& uid) { int id = Tools::ToInt(cb->id()); m_uidsToSign.push_back(id); + m_uidsToRevokeCertification.push_back(uid); } -void PopupCertifyUserId::OnEmailUnChecked(WCheckBox* cb) +void PopupCertifyUserId::OnEmailUnChecked(WCheckBox* cb, GpgME::UserID& uid) { - // Any tip to locate a known value in a vector without iterating over? const uint id = Tools::ToInt(cb->id()); - vector::iterator it; - for (it = m_uidsToSign.begin(); it != m_uidsToSign.end(); it++) + vector::iterator it = + std::find(m_uidsToSign.begin(), m_uidsToSign.end(), id); + if (it != m_uidsToSign.end()) + m_uidsToSign.erase(it); + + vector::iterator uit; + for (uit = m_uidsToRevokeCertification.begin(); + uit != m_uidsToRevokeCertification.end(); uit++) { - if ((*it) == id) + if ((*uit).uidhash() == uid.uidhash()) { - m_uidsToSign.erase(it); - return; + m_uidsToRevokeCertification.erase(uit); + break; } } + } void PopupCertifyUserId::OnCertifyOptionChecked(int id) @@ -250,3 +272,10 @@ void PopupCertifyUserId::OnCertifyOptionUnChecked(int id) { m_certifyOptions -= id; } + +void PopupCertifyUserId::OnButtonGroupWhat(WRadioButton* btn) +{ + m_gbOptions->setDisabled(m_bgWhat->checkedId() + == What::RevokeUidCertification); + +} diff --git a/PopupCertifyUserId.h b/PopupCertifyUserId.h index 32a6629..98a5773 100644 --- a/PopupCertifyUserId.h +++ b/PopupCertifyUserId.h @@ -19,28 +19,32 @@ #include #include #include +#include +#include #include +#include #include "TransientMessageWidget.h" using namespace Wt; /** - * A popup with required parameters to certify a key : + * A popup with required parameters to certify or revoke a key uid : *
    *
  • Signer's private keys
  • *
  • Target key user identities (email)
  • *
  • Signing options : Exportable and non-revocable
  • *
  • Passphrase for selected private key
  • *
- * The passphrase is cached by gpg-agent for default 10 mins. - * \n The popup hides the passphrase widget until a certify op fails. - * \n UserID::Validity:: lists many validity levels. How to selectively apply - * an arbitrary level ? Before signing, it's 'Unknown'. After signing, it's - * always 'Full'. + * \n For revocation, GnuPG >= 2.2.24 is required. */ class PopupCertifyUserId : public WPopupWidget { public: + + enum What + { + RevokeUidCertification = 0, CertifyUid + }; PopupCertifyUserId(WWidget * anchorWidget, TransientMessageWidget * txtMessage, const WLength& width = 500); virtual ~PopupCertifyUserId(); @@ -102,6 +106,27 @@ public: return m_uidsToSign; } + /** + * Get the certifications to revoke. + * \n GPGME >= 1.15.0 is required. It expects + * it as a vector of GpgME::UserID, instead of a vector of indices used in + * GetUidsToSign(). + * @return + */ + vector& GetUidsToRevokeCertification() + { + return m_uidsToRevokeCertification; + } + + /** + * Certify selected user identities or revoke certifications. + * @return + */ + const What WhatToDo() const + { + return (What) m_bgWhat->checkedId(); + } + /** * Sum of option values *
    @@ -141,7 +166,10 @@ private: WPushButton * m_btnApply; vector m_uidsToSign; + vector m_uidsToRevokeCertification; int m_certifyOptions; + WGroupBox * m_gbOptions; + shared_ptr m_bgWhat; /** * Available private fingerprints in a combobox. The selected item is the * signing key. @@ -154,15 +182,17 @@ private: */ void PresentEmail(); /** - * Add the identity index in a vector. + * Add the identity index in a vector for certification. + * \n Add the ::UserID in a vector for signature revocation. * @param cb */ - void OnEmailChecked(WCheckBox * cb); + void OnEmailChecked(WCheckBox * cb, GpgME::UserID& uid); /** - * Removes the identity index in a vector. + * Removes the identity index from a vector for certification. + * \n Removes the ::UserID from a vector for signature revocation. * @param cb */ - void OnEmailUnChecked(WCheckBox * cb); + void OnEmailUnChecked(WCheckBox * cb, GpgME::UserID& uid); /** * Adds the option value in m_certifyOptions. * @param id @@ -173,6 +203,11 @@ private: * @param id */ void OnCertifyOptionUnChecked(int id); + /** + * Show certification options if certifying, else hide them. + * @param btn + */ + void OnButtonGroupWhat(WRadioButton * btn); }; #endif /* POPUPCERTIFYUSERID_H */ diff --git a/WTAPPROOT/K7/K7.xml b/WTAPPROOT/K7/K7.xml index 7dfca67..ed898d1 100644 --- a/WTAPPROOT/K7/K7.xml +++ b/WTAPPROOT/K7/K7.xml @@ -83,8 +83,10 @@ No email address is selected Apply Key succesfully certified - Key certification failed + Identity certification succesfully revoked Once set, this option cannot be removed. Use gpg cli for further edit. + Certify identities + Revoke certifications Click to be able to copy next diff --git a/WTAPPROOT/K7/K7_fr.xml b/WTAPPROOT/K7/K7_fr.xml index 04b6746..62af995 100644 --- a/WTAPPROOT/K7/K7_fr.xml +++ b/WTAPPROOT/K7/K7_fr.xml @@ -83,8 +83,10 @@ Aucun courriel n'est sélectionné Appliquer Succès de certification de la clé - Échec de certification de la clé + Succès de révocation de l'identité Une fois appliquée, cette option ne pourra plus être enlevée. Utilisez gpg en ligne de commande pour édition ultérieure. + Certifier les identités + Revoquer les certifications Cliquez pour pouvoir ensuite copier