Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PIM
Kleopatra
Commits
001b56b9
Commit
001b56b9
authored
Nov 12, 2020
by
Ingo Klöcker
Browse files
Allow creating an OpenPGP key for the keys on an OpenPGP card
GnuPG-bug-id: 5125
parent
c19a9e52
Pipeline
#41247
canceled with stage
in 6 minutes and 21 seconds
Changes
5
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/CMakeLists.txt
View file @
001b56b9
...
...
@@ -245,6 +245,7 @@ set(_kleopatra_SRCS
commands/setpivcardapplicationadministrationkeycommand.cpp
commands/certificatetopivcardcommand.cpp
commands/importcertificatefrompivcardcommand.cpp
commands/createopenpgpkeyfromcardkeyscommand.cpp
${
_kleopatra_uiserver_files
}
...
...
src/commands/createopenpgpkeyfromcardkeyscommand.cpp
0 → 100644
View file @
001b56b9
/* -*- mode: c++; c-basic-offset:4 -*-
commands/createopenpgpkeyfromcardkeyscommand.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "createopenpgpkeyfromcardkeyscommand.h"
#include "cardcommand_p.h"
#include "dialogs/adduseriddialog.h"
#include "smartcard/openpgpcard.h"
#include "smartcard/readerstatus.h"
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <KLocalizedString>
#include <QGpgME/Protocol>
#include <QGpgME/QuickJob>
#include <gpgme++/context.h>
#include <gpgme++/engineinfo.h>
#include <gpgme.h>
#include "kleopatra_debug.h"
using
namespace
Kleo
;
using
namespace
Kleo
::
Commands
;
using
namespace
Kleo
::
Dialogs
;
using
namespace
Kleo
::
SmartCard
;
using
namespace
GpgME
;
using
namespace
QGpgME
;
class
CreateOpenPGPKeyFromCardKeysCommand
::
Private
:
public
CardCommand
::
Private
{
friend
class
::
Kleo
::
Commands
::
CreateOpenPGPKeyFromCardKeysCommand
;
CreateOpenPGPKeyFromCardKeysCommand
*
q_func
()
const
{
return
static_cast
<
CreateOpenPGPKeyFromCardKeysCommand
*>
(
q
);
}
public:
explicit
Private
(
CreateOpenPGPKeyFromCardKeysCommand
*
qq
,
const
std
::
string
&
serialNumber
,
const
std
::
string
&
appName
,
QWidget
*
parent
);
~
Private
();
private:
void
start
();
void
slotDialogAccepted
();
void
slotDialogRejected
();
void
slotResult
(
const
Error
&
err
);
void
ensureDialogCreated
();
private:
std
::
string
appName
;
QPointer
<
AddUserIDDialog
>
dialog
;
};
CreateOpenPGPKeyFromCardKeysCommand
::
Private
*
CreateOpenPGPKeyFromCardKeysCommand
::
d_func
()
{
return
static_cast
<
Private
*>
(
d
.
get
());
}
const
CreateOpenPGPKeyFromCardKeysCommand
::
Private
*
CreateOpenPGPKeyFromCardKeysCommand
::
d_func
()
const
{
return
static_cast
<
const
Private
*>
(
d
.
get
());
}
#define d d_func()
#define q q_func()
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
Private
(
CreateOpenPGPKeyFromCardKeysCommand
*
qq
,
const
std
::
string
&
serialNumber
,
const
std
::
string
&
appName_
,
QWidget
*
parent
)
:
CardCommand
::
Private
(
qq
,
serialNumber
,
parent
)
,
appName
(
appName_
)
{
}
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::~
Private
()
{
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
start
()
{
const
auto
pgpCard
=
ReaderStatus
::
instance
()
->
getCard
<
OpenPGPCard
>
(
serialNumber
());
if
(
!
pgpCard
)
{
error
(
i18n
(
"Failed to find the OpenPGP card with the serial number: %1"
,
QString
::
fromStdString
(
serialNumber
())));
finished
();
return
;
}
const
auto
signingKey
=
KeyCache
::
instance
()
->
findByKeyIDOrFingerprint
(
pgpCard
->
sigFpr
());
if
(
!
signingKey
.
isNull
())
{
const
QString
message
=
i18nc
(
"@info"
,
"<p>There is already an OpenPGP key corresponding to the signing key on this card:</p><p>%1<p>"
"<p>Do you still want to create an OpenPGP key for the card keys?</p>"
,
Formatting
::
summaryLine
(
signingKey
));
const
auto
choice
=
KMessageBox
::
warningContinueCancel
(
parentWidgetOrView
(),
message
,
i18nc
(
"@title:window"
,
"Create OpenPGP Key"
),
KStandardGuiItem
::
cont
(),
KStandardGuiItem
::
cancel
(),
QString
(),
KMessageBox
::
Notify
);
if
(
choice
!=
KMessageBox
::
Continue
)
{
finished
();
return
;
}
}
ensureDialogCreated
();
dialog
->
setWindowTitle
(
i18n
(
"Enter User ID"
));
dialog
->
setName
(
pgpCard
->
cardHolder
());
dialog
->
show
();
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
slotDialogAccepted
()
{
if
(
!
(
engineInfo
(
GpgEngine
).
engineVersion
()
<
"2.3.0"
))
{
Error
err
;
std
::
unique_ptr
<
Context
>
c
=
Context
::
createForEngine
(
AssuanEngine
,
&
err
);
if
(
err
.
code
()
==
GPG_ERR_NOT_SUPPORTED
)
{
finished
();
return
;
}
auto
assuanContext
=
std
::
shared_ptr
<
Context
>
(
c
.
release
());
const
auto
resultSerialNumber
=
ReaderStatus
::
switchCard
(
assuanContext
,
serialNumber
(),
err
);
if
(
err
||
resultSerialNumber
!=
serialNumber
())
{
qCWarning
(
KLEOPATRA_LOG
)
<<
"Switching to card"
<<
QString
::
fromStdString
(
serialNumber
())
<<
"failed"
;
finished
();
return
;
}
const
auto
resultAppName
=
ReaderStatus
::
switchApp
(
assuanContext
,
serialNumber
(),
appName
,
err
);
if
(
err
||
resultAppName
!=
appName
)
{
qCWarning
(
KLEOPATRA_LOG
)
<<
"Switching card to"
<<
QString
::
fromStdString
(
appName
)
<<
"app failed"
;
finished
();
return
;
}
}
const
auto
backend
=
openpgp
();
if
(
!
backend
)
{
finished
();
return
;
}
QuickJob
*
const
job
=
backend
->
quickJob
();
if
(
!
job
)
{
finished
();
return
;
}
connect
(
job
,
SIGNAL
(
result
(
GpgME
::
Error
)),
q
,
SLOT
(
slotResult
(
GpgME
::
Error
)));
const
QString
userID
=
Formatting
::
prettyNameAndEMail
(
OpenPGP
,
QString
(),
dialog
->
name
(),
dialog
->
email
(),
dialog
->
comment
());
const
QDateTime
expires
=
QDateTime
();
const
unsigned
int
flags
=
GPGME_CREATE_FORCE
;
job
->
startCreate
(
userID
,
"card"
,
expires
,
Key
(),
flags
);
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
slotDialogRejected
()
{
canceled
();
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
slotResult
(
const
Error
&
err
)
{
if
(
err
.
isCanceled
())
{
// do nothing
}
else
if
(
err
)
{
error
(
i18nc
(
"@info"
,
"Creating an OpenPGP key from the card keys failed: %1"
,
QString
::
fromUtf8
(
err
.
asString
())),
i18nc
(
"@title"
,
"Error"
));
}
else
{
information
(
i18nc
(
"@info"
,
"Successfully generated an OpenPGP key from the card keys."
),
i18nc
(
"@title"
,
"Success"
));
}
finished
();
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
Private
::
ensureDialogCreated
()
{
if
(
dialog
)
{
return
;
}
dialog
=
new
AddUserIDDialog
;
applyWindowID
(
dialog
);
dialog
->
setAttribute
(
Qt
::
WA_DeleteOnClose
);
connect
(
dialog
,
SIGNAL
(
accepted
()),
q
,
SLOT
(
slotDialogAccepted
()));
connect
(
dialog
,
SIGNAL
(
rejected
()),
q
,
SLOT
(
slotDialogRejected
()));
}
CreateOpenPGPKeyFromCardKeysCommand
::
CreateOpenPGPKeyFromCardKeysCommand
(
const
std
::
string
&
serialNumber
,
const
std
::
string
&
appName
,
QWidget
*
parent
)
:
CardCommand
(
new
Private
(
this
,
serialNumber
,
appName
,
parent
))
{
}
CreateOpenPGPKeyFromCardKeysCommand
::~
CreateOpenPGPKeyFromCardKeysCommand
()
{
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
doStart
()
{
d
->
start
();
}
void
CreateOpenPGPKeyFromCardKeysCommand
::
doCancel
()
{
}
#undef d
#undef q
#include "moc_createopenpgpkeyfromcardkeyscommand.cpp"
src/commands/createopenpgpkeyfromcardkeyscommand.h
0 → 100644
View file @
001b56b9
/* -*- mode: c++; c-basic-offset:4 -*-
commands/createopenpgpkeyfromcardkeyscommand.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef __KLEOPATRA_COMMANDS_CREATEOPENPGPKEYFROMCARDKEYSCOMMAND_H__
#define __KLEOPATRA_COMMANDS_CREATEOPENPGPKEYFROMCARDKEYSCOMMAND_H__
#include <commands/cardcommand.h>
namespace
Kleo
{
namespace
Commands
{
class
CreateOpenPGPKeyFromCardKeysCommand
:
public
CardCommand
{
Q_OBJECT
public:
explicit
CreateOpenPGPKeyFromCardKeysCommand
(
const
std
::
string
&
serialNumber
,
const
std
::
string
&
appName
,
QWidget
*
parent
=
nullptr
);
~
CreateOpenPGPKeyFromCardKeysCommand
()
override
;
private:
void
doStart
()
override
;
void
doCancel
()
override
;
private:
class
Private
;
inline
Private
*
d_func
();
inline
const
Private
*
d_func
()
const
;
Q_PRIVATE_SLOT
(
d_func
(),
void
slotDialogAccepted
())
Q_PRIVATE_SLOT
(
d_func
(),
void
slotDialogRejected
())
Q_PRIVATE_SLOT
(
d_func
(),
void
slotResult
(
GpgME
::
Error
))
};
}
// namespace Commands
}
// namespace Kleo
#endif // __KLEOPATRA_COMMANDS_CREATEOPENPGPKEYFROMCARDKEYSCOMMAND_H__
src/view/pgpcardwidget.cpp
View file @
001b56b9
...
...
@@ -12,6 +12,7 @@
#include "kleopatra_debug.h"
#include "commands/changepincommand.h"
#include "commands/createopenpgpkeyfromcardkeyscommand.h"
#include "smartcard/openpgpcard.h"
#include "smartcard/readerstatus.h"
...
...
@@ -105,6 +106,7 @@ PGPCardWidget::PGPCardWidget(QWidget *parent):
mEncryptionKey
(
new
QLabel
(
this
)),
mAuthKey
(
new
QLabel
(
this
)),
mUrlLabel
(
new
QLabel
(
this
)),
mKeyForCardKeysButton
(
new
QPushButton
(
this
)),
mCardIsEmpty
(
false
)
{
auto
grid
=
new
QGridLayout
;
...
...
@@ -201,6 +203,11 @@ PGPCardWidget::PGPCardWidget(QWidget *parent):
actionLayout
->
addWidget
(
resetCodeButton
);
connect
(
resetCodeButton
,
&
QPushButton
::
clicked
,
this
,
[
this
]
()
{
doChangePin
(
OpenPGPCard
::
resetCodeKeyRef
());
});
mKeyForCardKeysButton
->
setText
(
i18n
(
"Create Key for Card Keys"
));
mKeyForCardKeysButton
->
setToolTip
(
i18n
(
"Create an OpenPGP key for the keys stored on the card."
));
actionLayout
->
addWidget
(
mKeyForCardKeysButton
);
connect
(
mKeyForCardKeysButton
,
&
QPushButton
::
clicked
,
this
,
&
PGPCardWidget
::
createKeyFromCardKeys
);
actionLayout
->
addStretch
(
-
1
);
grid
->
addLayout
(
actionLayout
,
row
++
,
0
,
1
,
4
);
...
...
@@ -233,6 +240,8 @@ void PGPCardWidget::setCard(const OpenPGPCard *card)
updateKey
(
mEncryptionKey
,
card
->
encFpr
());
updateKey
(
mAuthKey
,
card
->
authFpr
());
mCardIsEmpty
=
card
->
authFpr
().
empty
()
&&
card
->
sigFpr
().
empty
()
&&
card
->
encFpr
().
empty
();
mKeyForCardKeysButton
->
setEnabled
(
!
mCardIsEmpty
);
}
void
PGPCardWidget
::
doChangePin
(
const
std
::
string
&
keyRef
)
...
...
@@ -467,6 +476,17 @@ void PGPCardWidget::changeUrlResult(const GpgME::Error &err)
}
}
void
PGPCardWidget
::
createKeyFromCardKeys
()
{
auto
cmd
=
new
CreateOpenPGPKeyFromCardKeysCommand
(
mRealSerial
,
OpenPGPCard
::
AppName
,
this
);
this
->
setEnabled
(
false
);
connect
(
cmd
,
&
CreateOpenPGPKeyFromCardKeysCommand
::
finished
,
this
,
[
this
]()
{
this
->
setEnabled
(
true
);
});
cmd
->
start
();
}
void
PGPCardWidget
::
updateKey
(
QLabel
*
label
,
const
std
::
string
&
fpr
)
{
label
->
setText
(
QString
::
fromStdString
(
fpr
));
...
...
src/view/pgpcardwidget.h
View file @
001b56b9
...
...
@@ -15,6 +15,7 @@
#include <string>
class
QLabel
;
class
QPushButton
;
namespace
Kleo
{
...
...
@@ -41,6 +42,7 @@ public Q_SLOTS:
void
changeNameResult
(
const
GpgME
::
Error
&
err
);
void
changeUrlRequested
();
void
changeUrlResult
(
const
GpgME
::
Error
&
err
);
void
createKeyFromCardKeys
();
private:
void
doChangePin
(
const
std
::
string
&
keyRef
);
...
...
@@ -52,6 +54,7 @@ private:
*
mEncryptionKey
=
nullptr
,
*
mAuthKey
=
nullptr
,
*
mUrlLabel
=
nullptr
;
QPushButton
*
mKeyForCardKeysButton
=
nullptr
;
QString
mUrl
;
bool
mCardIsEmpty
=
false
;
bool
mIs21
=
false
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment