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
libkleo
Commits
1fd410fb
Commit
1fd410fb
authored
Mar 24, 2021
by
Ingo Klöcker
Browse files
Move implementation of KeyResolverCore to separate file
GnuPG-bug-id: 5283
parent
000d602a
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/CMakeLists.txt
View file @
1fd410fb
...
...
@@ -28,6 +28,7 @@ set(libkleo_core_SRCS
kleo/keyfiltermanager.cpp
kleo/keygroup.cpp
kleo/keyresolver.cpp
kleo/keyresolvercore.cpp
kleo/kleoexception.cpp
kleo/oidmap.cpp
models/keycache.cpp
...
...
src/kleo/keyresolver.cpp
View file @
1fd410fb
...
...
@@ -29,75 +29,6 @@
using
namespace
Kleo
;
using
namespace
GpgME
;
namespace
{
static
inline
bool
ValidEncryptionKey
(
const
Key
&
key
)
{
if
(
key
.
isNull
()
||
key
.
isRevoked
()
||
key
.
isExpired
()
||
key
.
isDisabled
()
||
!
key
.
canEncrypt
())
{
return
false
;
}
return
true
;
}
static
inline
bool
ValidSigningKey
(
const
Key
&
key
)
{
if
(
key
.
isNull
()
||
key
.
isRevoked
()
||
key
.
isExpired
()
||
key
.
isDisabled
()
||
!
key
.
canSign
()
||
!
key
.
hasSecret
())
{
return
false
;
}
return
true
;
}
}
// namespace
class
KeyResolverCore
::
Private
{
public:
Private
(
KeyResolverCore
*
qq
,
bool
enc
,
bool
sig
,
Protocol
fmt
)
:
q
(
qq
)
,
mFormat
(
fmt
)
,
mEncrypt
(
enc
)
,
mSign
(
sig
)
,
mCache
(
KeyCache
::
instance
())
,
mPreferredProtocol
(
UnknownProtocol
)
,
mMinimumValidity
(
UserID
::
Marginal
)
,
mCompliance
(
Formatting
::
complianceMode
())
{
}
~
Private
()
=
default
;
bool
isAcceptableSigningKey
(
const
Key
&
key
);
bool
isAcceptableEncryptionKey
(
const
Key
&
key
,
const
QString
&
address
=
QString
());
void
addRecipients
(
const
QStringList
&
addresses
);
void
resolveOverrides
();
void
resolveSign
(
Protocol
proto
);
void
setSigningKeys
(
const
QStringList
&
fingerprints
);
void
resolveEnc
(
Protocol
proto
);
KeyResolverCore
*
const
q
;
QString
mSender
;
QStringList
mRecipients
;
QMap
<
Protocol
,
std
::
vector
<
Key
>>
mSigKeys
;
QMap
<
Protocol
,
QMap
<
QString
,
std
::
vector
<
Key
>>>
mEncKeys
;
QMap
<
Protocol
,
QMap
<
QString
,
QStringList
>>
mOverrides
;
QStringList
mUnresolvedPGP
;
QStringList
mUnresolvedCMS
;
Protocol
mFormat
;
QStringList
mFatalErrors
;
bool
mEncrypt
;
bool
mSign
;
// The cache is needed as a member variable to avoid rebuilding
// it between calls if we are the only user.
std
::
shared_ptr
<
const
KeyCache
>
mCache
;
Protocol
mPreferredProtocol
;
int
mMinimumValidity
;
QString
mCompliance
;
};
class
KeyResolver
::
Private
{
public:
...
...
@@ -136,230 +67,6 @@ public:
Protocol
mPreferredProtocol
;
};
bool
KeyResolverCore
::
Private
::
isAcceptableSigningKey
(
const
Key
&
key
)
{
if
(
!
ValidSigningKey
(
key
))
{
return
false
;
}
if
(
mCompliance
==
QLatin1String
(
"de-vs"
))
{
if
(
!
Formatting
::
isKeyDeVs
(
key
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Rejected sig key"
<<
key
.
primaryFingerprint
()
<<
"because it is not de-vs compliant."
;
return
false
;
}
}
return
true
;
}
bool
KeyResolverCore
::
Private
::
isAcceptableEncryptionKey
(
const
Key
&
key
,
const
QString
&
address
)
{
if
(
!
ValidEncryptionKey
(
key
))
{
return
false
;
}
if
(
mCompliance
==
QLatin1String
(
"de-vs"
))
{
if
(
!
Formatting
::
isKeyDeVs
(
key
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Rejected enc key"
<<
key
.
primaryFingerprint
()
<<
"because it is not de-vs compliant."
;
return
false
;
}
}
if
(
address
.
isEmpty
())
{
return
true
;
}
for
(
const
auto
&
uid
:
key
.
userIDs
())
{
if
(
uid
.
addrSpec
()
==
address
.
toStdString
())
{
if
(
uid
.
validity
()
>=
mMinimumValidity
)
{
return
true
;
}
}
}
return
false
;
}
void
KeyResolverCore
::
Private
::
addRecipients
(
const
QStringList
&
addresses
)
{
if
(
!
mEncrypt
)
{
return
;
}
// Internally we work with normalized addresses. Normalization
// matches the gnupg one.
for
(
const
auto
&
addr
:
addresses
)
{
// PGP Uids are defined to be UTF-8 (RFC 4880 §5.11)
const
auto
normalized
=
UserID
::
addrSpecFromString
(
addr
.
toUtf8
().
constData
());
if
(
normalized
.
empty
())
{
// should not happen bug in the caller, non localized
// error for bug reporting.
mFatalErrors
<<
QStringLiteral
(
"The mail address for '%1' could not be extracted"
).
arg
(
addr
);
continue
;
}
const
QString
normStr
=
QString
::
fromUtf8
(
normalized
.
c_str
());
// Initially mark them as unresolved for both protocols
if
(
!
mUnresolvedCMS
.
contains
(
normStr
))
{
mUnresolvedCMS
<<
normStr
;
}
if
(
!
mUnresolvedPGP
.
contains
(
normStr
))
{
mUnresolvedPGP
<<
normStr
;
}
mRecipients
<<
normStr
;
}
}
// Apply the overrides this is also where specific formats come in
void
KeyResolverCore
::
Private
::
resolveOverrides
()
{
if
(
!
mEncrypt
)
{
// No encryption we are done.
return
;
}
for
(
Protocol
fmt
:
mOverrides
.
keys
())
{
// Iterate over the crypto message formats
if
(
mFormat
!=
UnknownProtocol
&&
mFormat
!=
fmt
&&
fmt
!=
UnknownProtocol
)
{
// Skip overrides for the wrong format
continue
;
}
for
(
const
auto
&
addr
:
mOverrides
[
fmt
].
keys
())
{
// For all address overrides of this format.
for
(
const
auto
&
fprOrId
:
mOverrides
[
fmt
][
addr
])
{
// For all the keys configured for this address.
const
auto
key
=
mCache
->
findByKeyIDOrFingerprint
(
fprOrId
.
toUtf8
().
constData
());
if
(
key
.
isNull
())
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Failed to find override key for:"
<<
addr
<<
"fpr:"
<<
fprOrId
;
continue
;
}
// Now add it to the resolved keys and remove it from our list
// of unresolved keys.
if
(
!
mRecipients
.
contains
(
addr
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Override provided for an address that is "
"neither sender nor recipient. Address: "
<<
addr
;
continue
;
}
Protocol
resolvedFmt
=
fmt
;
if
(
fmt
==
UnknownProtocol
)
{
// Take the format from the key.
resolvedFmt
=
key
.
protocol
();
}
auto
recpMap
=
mEncKeys
.
value
(
resolvedFmt
);
auto
keys
=
recpMap
.
value
(
addr
);
keys
.
push_back
(
key
);
recpMap
.
insert
(
addr
,
keys
);
mEncKeys
.
insert
(
resolvedFmt
,
recpMap
);
// Now we can remove it from our unresolved lists.
if
(
key
.
protocol
()
==
OpenPGP
)
{
mUnresolvedPGP
.
removeAll
(
addr
);
}
else
{
mUnresolvedCMS
.
removeAll
(
addr
);
}
qCDebug
(
LIBKLEO_LOG
)
<<
"Override"
<<
addr
<<
Formatting
::
displayName
(
resolvedFmt
)
<<
fprOrId
;
}
}
}
}
void
KeyResolverCore
::
Private
::
resolveSign
(
Protocol
proto
)
{
if
(
mSigKeys
.
contains
(
proto
))
{
// Explicitly set
return
;
}
const
auto
keys
=
mCache
->
findBestByMailBox
(
mSender
.
toUtf8
().
constData
(),
proto
,
true
,
false
);
for
(
const
auto
&
key
:
keys
)
{
if
(
key
.
isNull
())
{
continue
;
}
if
(
!
isAcceptableSigningKey
(
key
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Unacceptable signing key"
<<
key
.
primaryFingerprint
()
<<
"for"
<<
mSender
;
return
;
}
}
if
(
!
keys
.
empty
()
&&
!
keys
[
0
].
isNull
())
{
mSigKeys
.
insert
(
proto
,
keys
);
}
}
void
KeyResolverCore
::
Private
::
setSigningKeys
(
const
QStringList
&
fingerprints
)
{
if
(
mSign
)
{
for
(
const
auto
&
fpr
:
fingerprints
)
{
const
auto
key
=
mCache
->
findByKeyIDOrFingerprint
(
fpr
.
toUtf8
().
constData
());
if
(
key
.
isNull
())
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Failed to find signing key with fingerprint"
<<
fpr
;
continue
;
}
auto
list
=
mSigKeys
.
value
(
key
.
protocol
());
list
.
push_back
(
key
);
mSigKeys
.
insert
(
key
.
protocol
(),
list
);
}
}
}
// Try to find matching keys in the provided protocol for the unresolved addresses
// only updates the any maps.
void
KeyResolverCore
::
Private
::
resolveEnc
(
Protocol
proto
)
{
auto
encMap
=
mEncKeys
.
value
(
proto
);
QMutableStringListIterator
it
((
proto
==
Protocol
::
OpenPGP
)
?
mUnresolvedPGP
:
mUnresolvedCMS
);
while
(
it
.
hasNext
())
{
const
QString
addr
=
it
.
next
();
const
auto
keys
=
mCache
->
findBestByMailBox
(
addr
.
toUtf8
().
constData
(),
proto
,
false
,
true
);
if
(
keys
.
empty
()
||
keys
[
0
].
isNull
())
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Failed to find any"
<<
(
proto
==
Protocol
::
OpenPGP
?
"OpenPGP"
:
"CMS"
)
<<
"key for: "
<<
addr
;
continue
;
}
if
(
keys
.
size
()
==
1
)
{
if
(
!
isAcceptableEncryptionKey
(
keys
[
0
],
addr
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"key for: "
<<
addr
<<
keys
[
0
].
primaryFingerprint
()
<<
"has not enough validity"
;
continue
;
}
}
else
{
// If we have one unacceptable group key we reject the
// whole group to avoid the situation where one key is
// skipped or the operation fails.
//
// We are in Autoresolve land here. In the GUI we
// will also show unacceptable group keys so that the
// user can see which key is not acceptable.
bool
unacceptable
=
false
;
for
(
const
auto
&
key
:
keys
)
{
if
(
!
isAcceptableEncryptionKey
(
key
))
{
qCDebug
(
LIBKLEO_LOG
)
<<
"group key for: "
<<
addr
<<
keys
[
0
].
primaryFingerprint
()
<<
"has not enough validity"
;
unacceptable
=
true
;
break
;
}
}
if
(
unacceptable
)
{
continue
;
}
}
encMap
.
insert
(
addr
,
keys
);
for
(
const
auto
&
k
:
keys
)
{
if
(
!
k
.
isNull
())
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Resolved encrypt to"
<<
addr
<<
"with key"
<<
k
.
primaryFingerprint
();
}
}
it
.
remove
();
}
mEncKeys
.
insert
(
proto
,
encMap
);
}
void
KeyResolver
::
Private
::
showApprovalDialog
(
QWidget
*
parent
)
{
const
QString
sender
=
mCore
.
normalizedSender
();
...
...
@@ -508,80 +215,6 @@ void KeyResolver::Private::dialogAccepted()
Q_EMIT
q
->
keysResolved
(
true
,
false
);
}
KeyResolverCore
::
KeyResolverCore
(
bool
encrypt
,
bool
sign
,
Protocol
fmt
)
:
d
(
new
Private
(
this
,
encrypt
,
sign
,
fmt
))
{
}
KeyResolverCore
::~
KeyResolverCore
()
=
default
;
bool
KeyResolverCore
::
resolve
()
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Starting "
;
if
(
!
d
->
mSign
&&
!
d
->
mEncrypt
)
{
// nothing to do
return
true
;
}
// First resolve through overrides
d
->
resolveOverrides
();
// Then look for signing / encryption keys
if
(
d
->
mFormat
!=
CMS
)
{
d
->
resolveSign
(
OpenPGP
);
d
->
resolveEnc
(
OpenPGP
);
}
bool
pgpOnly
=
d
->
mUnresolvedPGP
.
empty
()
&&
(
!
d
->
mSign
||
d
->
mSigKeys
.
contains
(
OpenPGP
));
if
(
d
->
mFormat
!=
OpenPGP
)
{
d
->
resolveSign
(
CMS
);
d
->
resolveEnc
(
CMS
);
}
bool
cmsOnly
=
d
->
mUnresolvedCMS
.
empty
()
&&
(
!
d
->
mSign
||
d
->
mSigKeys
.
contains
(
CMS
));
// Check if we need the user to select different keys.
bool
needsUser
=
false
;
if
(
!
pgpOnly
&&
!
cmsOnly
)
{
for
(
const
auto
&
unresolved
:
d
->
mUnresolvedPGP
)
{
if
(
d
->
mUnresolvedCMS
.
contains
(
unresolved
))
{
// We have at least one unresolvable key.
needsUser
=
true
;
break
;
}
}
if
(
d
->
mSign
)
{
// So every recipient could be resolved through
// a combination of PGP and S/MIME do we also
// have signing keys for both?
needsUser
|=
!
(
d
->
mSigKeys
.
contains
(
OpenPGP
)
&&
d
->
mSigKeys
.
contains
(
CMS
));
}
}
if
(
!
needsUser
)
{
if
(
pgpOnly
&&
cmsOnly
)
{
if
(
d
->
mPreferredProtocol
==
CMS
)
{
d
->
mSigKeys
.
remove
(
OpenPGP
);
d
->
mEncKeys
.
remove
(
OpenPGP
);
}
else
{
d
->
mSigKeys
.
remove
(
CMS
);
d
->
mEncKeys
.
remove
(
CMS
);
}
}
else
if
(
pgpOnly
)
{
d
->
mSigKeys
.
remove
(
CMS
);
d
->
mEncKeys
.
remove
(
CMS
);
}
else
if
(
cmsOnly
)
{
d
->
mSigKeys
.
remove
(
OpenPGP
);
d
->
mEncKeys
.
remove
(
OpenPGP
);
}
qCDebug
(
LIBKLEO_LOG
)
<<
"Automatic key resolution done."
;
return
true
;
}
return
false
;
}
void
KeyResolver
::
start
(
bool
showApproval
,
QWidget
*
parentWidget
)
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Starting "
;
...
...
@@ -608,86 +241,31 @@ KeyResolver::KeyResolver(bool encrypt, bool sign, Protocol fmt, bool allowMixed)
Kleo
::
KeyResolver
::~
KeyResolver
()
=
default
;
void
KeyResolverCore
::
setRecipients
(
const
QStringList
&
addresses
)
{
d
->
addRecipients
(
addresses
);
}
void
KeyResolver
::
setRecipients
(
const
QStringList
&
addresses
)
{
d
->
mCore
.
setRecipients
(
addresses
);
}
void
KeyResolverCore
::
setSender
(
const
QString
&
address
)
{
const
auto
normalized
=
UserID
::
addrSpecFromString
(
address
.
toUtf8
().
constData
());
if
(
normalized
.
empty
())
{
// should not happen bug in the caller, non localized
// error for bug reporting.
d
->
mFatalErrors
<<
QStringLiteral
(
"The sender address '%1' could not be extracted"
).
arg
(
address
);
return
;
}
const
auto
normStr
=
QString
::
fromUtf8
(
normalized
.
c_str
());
if
(
d
->
mSign
)
{
d
->
mSender
=
normStr
;
}
d
->
addRecipients
({
address
});
}
void
KeyResolver
::
setSender
(
const
QString
&
address
)
{
d
->
mCore
.
setSender
(
address
);
}
QString
KeyResolverCore
::
normalizedSender
()
const
{
return
d
->
mSender
;
}
void
KeyResolverCore
::
setOverrideKeys
(
const
QMap
<
Protocol
,
QMap
<
QString
,
QStringList
>
>
&
overrides
)
{
QMap
<
QString
,
QStringList
>
normalizedOverrides
;
for
(
const
auto
fmt
:
overrides
.
keys
())
{
for
(
const
auto
&
addr
:
overrides
[
fmt
].
keys
())
{
const
auto
normalized
=
QString
::
fromUtf8
(
UserID
::
addrSpecFromString
(
addr
.
toUtf8
().
constData
()).
c_str
());
const
auto
fingerprints
=
overrides
[
fmt
][
addr
];
normalizedOverrides
.
insert
(
addr
,
fingerprints
);
}
d
->
mOverrides
.
insert
(
fmt
,
normalizedOverrides
);
}
}
void
KeyResolver
::
setOverrideKeys
(
const
QMap
<
Protocol
,
QMap
<
QString
,
QStringList
>
>
&
overrides
)
{
d
->
mCore
.
setOverrideKeys
(
overrides
);
}
void
KeyResolverCore
::
setSigningKeys
(
const
QStringList
&
fingerprints
)
{
d
->
setSigningKeys
(
fingerprints
);
}
void
KeyResolver
::
setSigningKeys
(
const
QStringList
&
fingerprints
)
{
d
->
mCore
.
setSigningKeys
(
fingerprints
);
}
QMap
<
Protocol
,
QMap
<
QString
,
std
::
vector
<
Key
>
>
>
KeyResolverCore
::
encryptionKeys
()
const
{
return
d
->
mEncKeys
;
}
QMap
<
Protocol
,
QMap
<
QString
,
std
::
vector
<
Key
>
>
>
KeyResolver
::
encryptionKeys
()
const
{
return
d
->
mCore
.
encryptionKeys
();
}
QMap
<
Protocol
,
std
::
vector
<
Key
>
>
KeyResolverCore
::
signingKeys
()
const
{
return
d
->
mSigKeys
;
}
QMap
<
Protocol
,
std
::
vector
<
Key
>
>
KeyResolver
::
signingKeys
()
const
{
return
d
->
mCore
.
signingKeys
();
...
...
@@ -698,33 +276,12 @@ void KeyResolver::setDialogWindowFlags(Qt::WindowFlags flags)
d
->
mDialogWindowFlags
=
flags
;
}
void
KeyResolverCore
::
setPreferredProtocol
(
Protocol
proto
)
{
d
->
mPreferredProtocol
=
proto
;
}
void
KeyResolver
::
setPreferredProtocol
(
Protocol
proto
)
{
d
->
mCore
.
setPreferredProtocol
(
proto
);
}
void
KeyResolverCore
::
setMinimumValidity
(
int
validity
)
{
d
->
mMinimumValidity
=
validity
;
}
void
KeyResolver
::
setMinimumValidity
(
int
validity
)
{
d
->
mCore
.
setMinimumValidity
(
validity
);
}
QStringList
KeyResolverCore
::
unresolvedRecipients
(
GpgME
::
Protocol
protocol
)
const
{
if
(
protocol
==
OpenPGP
)
{
return
d
->
mUnresolvedPGP
;
}
if
(
protocol
==
CMS
)
{
return
d
->
mUnresolvedCMS
;
}
return
{};
}
src/kleo/keyresolvercore.cpp
0 → 100644
View file @
1fd410fb
/* -*- c++ -*-
kleo/keyresolvercore.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
Based on kpgp.cpp
SPDX-FileCopyrightText: 2001, 2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "keyresolvercore.h"
#include "models/keycache.h"
#include "utils/formatting.h"
#include <gpgme++/key.h>
#include "libkleo_debug.h"
using
namespace
Kleo
;
using
namespace
GpgME
;
namespace
{
static
inline
bool
ValidEncryptionKey
(
const
Key
&
key
)
{
if
(
key
.
isNull
()
||
key
.
isRevoked
()
||
key
.
isExpired
()
||
key
.
isDisabled
()
||
!
key
.
canEncrypt
())
{
return
false
;
}
return
true
;
}
static
inline
bool
ValidSigningKey
(
const
Key
&
key
)
{
if
(
key
.
isNull
()
||
key
.
isRevoked
()
||
key
.
isExpired
()
||
key
.
isDisabled
()
||
!
key
.
canSign
()
||
!
key
.
hasSecret
())
{
return
false
;
}
return
true
;
}
}
// namespace
class
KeyResolverCore
::
Private
{
public:
Private
(
KeyResolverCore
*
qq
,
bool
enc
,
bool
sig
,
Protocol
fmt
)
:
q
(
qq
)
,
mFormat
(
fmt
)
,
mEncrypt
(
enc
)
,
mSign
(
sig
)
,
mCache
(
KeyCache
::
instance
())
,
mPreferredProtocol
(
UnknownProtocol
)
,
mMinimumValidity
(
UserID
::
Marginal
)
,
mCompliance
(
Formatting
::
complianceMode
())
{
}
~
Private
()
=
default
;
bool
isAcceptableSigningKey
(
const
Key
&
key
);
bool
isAcceptableEncryptionKey
(
const
Key
&
key
,
const
QString
&
address
=
QString
());
void
addRecipients
(
const
QStringList
&
addresses
);
void
resolveOverrides
();
void
resolveSign
(
Protocol
proto
);
void
setSigningKeys
(
const
QStringList
&
fingerprints
);
void
resolveEnc
(
Protocol
proto
);
KeyResolverCore
*
const
q
;
QString
mSender
;
QStringList
mRecipients
;
QMap
<
Protocol
,
std
::
vector
<
Key
>>
mSigKeys
;
QMap
<
Protocol
,
QMap
<
QString
,
std
::
vector
<
Key
>>>
mEncKeys
;
QMap
<
Protocol
,
QMap
<
QString
,
QStringList
>>
mOverrides
;
QStringList
mUnresolvedPGP
;
QStringList
mUnresolvedCMS
;
Protocol
mFormat
;
QStringList
mFatalErrors
;
bool
mEncrypt
;
bool
mSign
;
// The cache is needed as a member variable to avoid rebuilding
// it between calls if we are the only user.
std
::
shared_ptr
<
const
KeyCache
>
mCache
;
Protocol
mPreferredProtocol
;
int
mMinimumValidity
;
QString
mCompliance
;
};
bool
KeyResolverCore
::
Private
::
isAcceptableSigningKey
(
const
Key
&
key
)
{
if
(
!
ValidSigningKey
(
key
))
{