[pim/libkleo] /: Add new result messages for verification of data signatures
Ingo Klöcker <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 27dfd33c519584e4b898818b1177af8ee0bc8af3 by Ingo Klöcker, on behalf of Ingo Klöcker.
Committed on 28/07/2026 at 14:48.
Pushed by kloecker into branch 'master'.
Add new result messages for verification of data signatures
The idea is to put the most important information at the beginning of the
messages and to make the texts easier to understand.
GnuPG-bug-id: 7786
A +1 -0 autotests/fixtures/formattingtest-devs/gpg.conf
A +5 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
A +6 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/8AB6EE6EE71A4FDE697F7B93A974E0D744927CB9.key
A +5 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/92EB0FB90A75272045A8AE2048F81451B4210BA0.key
A +5 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
A +5 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d/0D012E85DAA3A2E54D3644314F0C6A0791B09409.key
A +6 -0 autotests/fixtures/formattingtest-devs/private-keys-v1.d/3570307CBB71A5963C13EEBD6E1C7F9F624F5011.key
A +- -- autotests/fixtures/formattingtest-devs/pubring.kbx
C +- -- autotests/fixtures/formattingtest-devs/trustdb.gpg [from: autotests/fixtures/formattingtest/trustdb.gpg - 065% similarity]
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/02568351FD0CBA128A5853F52DAAF07DD467013D.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/2F27FD27E9D510F62AC1CCAEEB5E9297C02441A7.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/49C08788026B09490AB8C61E1BA5BD34F0168912.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/5BB918A966B4DFC935B2944398B0A1830D6C5765.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/7C2F4985E196528A357E27E8EAC7ED56EB3F387B.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/C0808D77CA45FA2CD0C68211126EF37633EC7F31.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d/893F437224327960918B615160E155A8F54408DC.key
A +5 -0 autotests/fixtures/formattingtest/private-keys-v1.d/FCBC0683836DADC6B12E836B88D4FE3748C8B492.key
M +- -- autotests/fixtures/formattingtest/pubring.kbx
M +- -- autotests/fixtures/formattingtest/trustdb.gpg
M +209 -0 autotests/formattingtest.cpp
M +21 -0 autotests/formattingtest.qrc
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-all-good.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-all-good.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-key-expired.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-key-expired.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt.sig
A +2 -0 autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt.sig
A +1 -0 autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt
A +- -- autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt.sig
M +128 -9 src/utils/formatting.cpp
M +14 -0 src/utils/formatting.h
https://invent.kde.org/pim/libkleo/-/commit/27dfd33c519584e4b898818b1177af8ee0bc8af3
diff --git a/autotests/fixtures/formattingtest-devs/gpg.conf b/autotests/fixtures/formattingtest-devs/gpg.conf
new file mode 100644
index 00000000..2371a65d
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/gpg.conf
@@ -0,0 +1 @@
+compliance de-vs
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
new file mode 100644
index 00000000..cfd330dc
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
@@ -0,0 +1,5 @@
+Created: 20260723T123240
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #40CE9BD35B02D07A6877EE5B817F23BC538DF7547F99DB18E7205963193C013624#)
+ (d #46E47EE303D8CB7339837129A8E57A0177802AE9A01108AC0D7B8B34D206B5B8#)
+ ))
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/8AB6EE6EE71A4FDE697F7B93A974E0D744927CB9.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/8AB6EE6EE71A4FDE697F7B93A974E0D744927CB9.key
new file mode 100644
index 00000000..305a8fde
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/8AB6EE6EE71A4FDE697F7B93A974E0D744927CB9.key
@@ -0,0 +1,6 @@
+Created: 20260728T090226
+Key: (private-key (ecc (curve brainpoolP256r1)(q
+ #040E2FEBE9F6850CFFE1F9F3003D945C5E20F831429B1107F687C9E564C71924444B
+ 1B339B6C7BD12D450D6ABB2BEA1596BDB4EB75BCFB6F8DAB24A1F11786EBA3#)(d
+ #0099B7B47F446AEB8572096140C6F89A1C594F092A0D4AF981D75112089F4A69FA#)
+ ))
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/92EB0FB90A75272045A8AE2048F81451B4210BA0.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/92EB0FB90A75272045A8AE2048F81451B4210BA0.key
new file mode 100644
index 00000000..34402553
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/92EB0FB90A75272045A8AE2048F81451B4210BA0.key
@@ -0,0 +1,5 @@
+Created: 20260728T090226
+Key: (private-key (ecc (curve brainpoolP256r1)(q
+ #0409C1AFED7AA2C3F8A334FC67C81E8AC18095518DB49DEDADFC2BE218BBB7C06F30
+ 7A8BAFD14D9049E554061BB9483221D4025A85A9F39F3A642C3E5C4CADB253#)(d
+ #4EA5AB8133961C361F29B648A6BDF6681B77D914DF7D1DBA277A5D19872941FC#)))
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
new file mode 100644
index 00000000..121cc0e4
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
@@ -0,0 +1,5 @@
+Created: 20260723T123240
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #408B8C107B42DC73CD0021827B60250DC0653893C7EF83C4EEB32FA4563D2EA35D#)
+ (d #85916B2B6949DF0DBEDB48217B1CE89B1EF5386B16F2E5A4ABD4273BA5AB3BE4#)
+ ))
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d/0D012E85DAA3A2E54D3644314F0C6A0791B09409.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d/0D012E85DAA3A2E54D3644314F0C6A0791B09409.key
new file mode 100644
index 00000000..19373dd9
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d/0D012E85DAA3A2E54D3644314F0C6A0791B09409.key
@@ -0,0 +1,5 @@
+Created: 20260728T085917
+Key: (private-key (ecc (curve brainpoolP256r1)(q
+ #040DD7AB1A58F4E9FA67C905AA1158395D1B4592C30584A7B19DA211D2F93C1E1E10
+ 86830E1BAB5E4014CEE4A24A3E7B33B32955C1114668B93FB333B8F44CA9D2#)(d
+ #1735C5F677C2310064F5A3C2488B11DEB21116423E36A79109A0C6A4D5DE09E5#)))
diff --git a/autotests/fixtures/formattingtest-devs/private-keys-v1.d/3570307CBB71A5963C13EEBD6E1C7F9F624F5011.key b/autotests/fixtures/formattingtest-devs/private-keys-v1.d/3570307CBB71A5963C13EEBD6E1C7F9F624F5011.key
new file mode 100644
index 00000000..eb7a5821
--- /dev/null
+++ b/autotests/fixtures/formattingtest-devs/private-keys-v1.d/3570307CBB71A5963C13EEBD6E1C7F9F624F5011.key
@@ -0,0 +1,6 @@
+Created: 20260728T085917
+Key: (private-key (ecc (curve brainpoolP256r1)(q
+ #042E3AAFCD819E464F2F4BD3260E1B517C67B7ED8862E2E83CD5CB76A6ED73256C48
+ 1442425D10266FEDD080FE37A3DD65B14911DA6719671255AE752AECF82E27#)(d
+ #008B8A63FF6DED8392E5C87DAD8FE7E880FFE8FA0419EB5CB518B9082E9F7A203D#)
+ ))
diff --git a/autotests/fixtures/formattingtest-devs/pubring.kbx b/autotests/fixtures/formattingtest-devs/pubring.kbx
new file mode 100644
index 00000000..eeb65c41
Binary files /dev/null and b/autotests/fixtures/formattingtest-devs/pubring.kbx differ
diff --git a/autotests/fixtures/formattingtest/trustdb.gpg b/autotests/fixtures/formattingtest-devs/trustdb.gpg
similarity index 65%
copy from autotests/fixtures/formattingtest/trustdb.gpg
copy to autotests/fixtures/formattingtest-devs/trustdb.gpg
index 40c36747..56818d94 100644
Binary files a/autotests/fixtures/formattingtest/trustdb.gpg and b/autotests/fixtures/formattingtest-devs/trustdb.gpg differ
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/02568351FD0CBA128A5853F52DAAF07DD467013D.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/02568351FD0CBA128A5853F52DAAF07DD467013D.key
new file mode 100644
index 00000000..41e2f4b4
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/02568351FD0CBA128A5853F52DAAF07DD467013D.key
@@ -0,0 +1,5 @@
+Created: 20260723T094814
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #40F9069BA703145C7BDD5FC24034D79C23630EDC58702A80962CA648804CC92221#)
+ (d #7EDF466E9C299B366BEB52E2BC868B6C32F061A331B14C31CFE6FE2A56E9A1F0#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/2F27FD27E9D510F62AC1CCAEEB5E9297C02441A7.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/2F27FD27E9D510F62AC1CCAEEB5E9297C02441A7.key
new file mode 100644
index 00000000..fa69a31e
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/2F27FD27E9D510F62AC1CCAEEB5E9297C02441A7.key
@@ -0,0 +1,5 @@
+Created: 20260723T093000
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #40CA0B700A5EEE5CE8C0920E29FE86A4DE2003C0A85F250DC60D8CD1206E858112#)
+ (d #5A311E06BA2A3786C752F4E450C81973CDB57FBD511A42FCC12B2142E13D3E70#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/49C08788026B09490AB8C61E1BA5BD34F0168912.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/49C08788026B09490AB8C61E1BA5BD34F0168912.key
new file mode 100644
index 00000000..f383c1ee
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/49C08788026B09490AB8C61E1BA5BD34F0168912.key
@@ -0,0 +1,5 @@
+Created: 20260723T080455
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #40EE416EBAA129998B778FF992B917CA7FA99F5D08F30C27373B0997A618CEE042#)
+ (d #575653D6246AC07E9FF68B690C0B442D3B71FF33CD63619E72432D6212766280#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
new file mode 100644
index 00000000..cfd330dc
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/590C2F19E742888B23B109730B8E96F599555A51.key
@@ -0,0 +1,5 @@
+Created: 20260723T123240
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #40CE9BD35B02D07A6877EE5B817F23BC538DF7547F99DB18E7205963193C013624#)
+ (d #46E47EE303D8CB7339837129A8E57A0177802AE9A01108AC0D7B8B34D206B5B8#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/5BB918A966B4DFC935B2944398B0A1830D6C5765.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/5BB918A966B4DFC935B2944398B0A1830D6C5765.key
new file mode 100644
index 00000000..509ab568
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/5BB918A966B4DFC935B2944398B0A1830D6C5765.key
@@ -0,0 +1,5 @@
+Created: 20260723T080455
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #407F5EF34EFAD0A5A03490D50461546A2C0652400B10C12BEDF0501E97BF86265C#)
+ (d #4CC9C3B5B2536C2BBD5139456EB367CD500886066519C392098ADE242DF12685#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/7C2F4985E196528A357E27E8EAC7ED56EB3F387B.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/7C2F4985E196528A357E27E8EAC7ED56EB3F387B.key
new file mode 100644
index 00000000..c1947b75
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/7C2F4985E196528A357E27E8EAC7ED56EB3F387B.key
@@ -0,0 +1,5 @@
+Created: 20260723T094814
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #40CCE48C27C9EC107527AF453E7911DBB30D45DC34D306AA0FD021F451D393C48C#)
+ (d #E2D5500C237320BE028B3A9F3026B8EA5C1671ABFCEC51586C49FB8042725994#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
new file mode 100644
index 00000000..121cc0e4
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/9310657D17AE778CCF61AD119169BE0CA5F5741D.key
@@ -0,0 +1,5 @@
+Created: 20260723T123240
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #408B8C107B42DC73CD0021827B60250DC0653893C7EF83C4EEB32FA4563D2EA35D#)
+ (d #85916B2B6949DF0DBEDB48217B1CE89B1EF5386B16F2E5A4ABD4273BA5AB3BE4#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/C0808D77CA45FA2CD0C68211126EF37633EC7F31.key b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/C0808D77CA45FA2CD0C68211126EF37633EC7F31.key
new file mode 100644
index 00000000..b15556f7
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d-not-used-for-tests/C0808D77CA45FA2CD0C68211126EF37633EC7F31.key
@@ -0,0 +1,5 @@
+Created: 20260723T093000
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #403558FE2624F31E4D1D55967D0FDC466083CA004E80277DEC6830C7BF03193EE1#)
+ (d #CF8EC8BE9907DE2F5D30BF0B80D08AAC9CDC62B8758A270A8E481D3C8DCCE662#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d/893F437224327960918B615160E155A8F54408DC.key b/autotests/fixtures/formattingtest/private-keys-v1.d/893F437224327960918B615160E155A8F54408DC.key
new file mode 100644
index 00000000..4757900d
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d/893F437224327960918B615160E155A8F54408DC.key
@@ -0,0 +1,5 @@
+Created: 20260723T123008
+Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q
+ #409B2412C04388DF255A7BA67894D1433F7498874A5D581F6AB301E3CE80C840CE#)
+ (d #63EC59F1BD01FE9B5CE03EA30398D63BD1137D72A607AF03ADBE4AC2343954DE#)
+ ))
diff --git a/autotests/fixtures/formattingtest/private-keys-v1.d/FCBC0683836DADC6B12E836B88D4FE3748C8B492.key b/autotests/fixtures/formattingtest/private-keys-v1.d/FCBC0683836DADC6B12E836B88D4FE3748C8B492.key
new file mode 100644
index 00000000..d5b7b025
--- /dev/null
+++ b/autotests/fixtures/formattingtest/private-keys-v1.d/FCBC0683836DADC6B12E836B88D4FE3748C8B492.key
@@ -0,0 +1,5 @@
+Created: 20260723T123008
+Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q
+ #403471F1D4DC74BD255E11575D879FF839A35772B66F220F608931BD6225B0F240#)
+ (d #62DCDDF70318E612BC063B28561F5134187618AC8FE6F121DD1CBDB16C143618#)
+ ))
diff --git a/autotests/fixtures/formattingtest/pubring.kbx b/autotests/fixtures/formattingtest/pubring.kbx
index 44565310..3dda0bc3 100644
Binary files a/autotests/fixtures/formattingtest/pubring.kbx and b/autotests/fixtures/formattingtest/pubring.kbx differ
diff --git a/autotests/fixtures/formattingtest/trustdb.gpg b/autotests/fixtures/formattingtest/trustdb.gpg
index 40c36747..b1065b39 100644
Binary files a/autotests/fixtures/formattingtest/trustdb.gpg and b/autotests/fixtures/formattingtest/trustdb.gpg differ
diff --git a/autotests/formattingtest.cpp b/autotests/formattingtest.cpp
index ea50fcb1..8ed4422c 100644
--- a/autotests/formattingtest.cpp
+++ b/autotests/formattingtest.cpp
@@ -6,9 +6,14 @@
SPDX-License-Identifier: LGPL-2.0-or-later
*/
+#include <Libkleo/Compliance>
+#include <Libkleo/CryptoConfig>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
+#include <Libkleo/Test>
+#include <QGpgME/CryptoConfig>
+#include <QGpgME/Debug>
#include <QGpgME/ImportJob>
#include <QGpgME/Protocol>
#include <QGpgME/SignJob>
@@ -27,6 +32,11 @@ using namespace Kleo;
using namespace GpgME;
using namespace Qt::Literals::StringLiterals;
+namespace Kleo::Tests::DeVSCompliance
+{
+void forceUsageOfCompliance(bool active);
+}
+
// Curve 448 test key with signing subkey (this key has V5 fingerprints)
// pub ed448 2024-09-23 [SC]
// 1DE1960C29F97E6762C4EA341820DAAC045579921E0F30567354CCC69FD42A1D
@@ -76,6 +86,28 @@ static const char *clearsigned_using_primary_key_of_curve_448 =
"=1i3o\n"
"-----END PGP SIGNATURE-----\n";
+static const char *opaque_smime_signed_data =
+ "-----BEGIN SIGNED MESSAGE-----\n"
+ "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0B\n"
+ "BwGggCSABAlTaWduIG1lIQoAAAAAAAAxggLmMIIC4gIBATB+MHgxCzAJBgNVBAYT\n"
+ "AkRFMRYwFAYDVQQKEw1nMTAgQ29kZSBHbWJIMRAwDgYDVQQLEwdUZXN0bGFiMR4w\n"
+ "HAYDVQQDExVnMTAgQ29kZSBURVNUIENBIDIwMTkxHzAdBgkqhkiG9w0BCQEWEGlu\n"
+ "Zm9AZzEwY29kZS5jb20CAhoDMA0GCWCGSAFlAwQCAQUAoIG6MBgGCSqGSIb3DQEJ\n"
+ "AzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI2MDcyMjEyMjMzMlowLwYJ\n"
+ "KoZIhvcNAQkEMSIEIKmQZ0JOVOovrhBksV3YI2d7ilQAdZccUJYySVzZ0+tYME8G\n"
+ "CSqGSIb3DQEJDzFCMEAwCwYJYIZIAWUDBAEuMAsGCWCGSAFlAwQBBjALBglghkgB\n"
+ "ZQMEASowCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA0GCSqGSIb3DQEBAQUABIIB\n"
+ "gJ0L7QAD5cOvgW+qETBWZIUwnyFRwUdQuNMC71X1SCRJdIzRPecr38Tt0i2dGXA2\n"
+ "Y7b6SGy9gOmy+DfqQ7GKPAmDyVqA1+sMOMnsF8CCB3DWdYbOWI18WAoPV49XOdra\n"
+ "vVTdXzKgz91WgXjiMUaG8Rrq7kP0F5Yw3LStUKZzO6yOof/YnJQWL9kYo/04m5Lj\n"
+ "ZkdwGW1o+WmFUcDO1OIEkxNmHWa/6wDlROT4HqH3ptwhXE9rMj8hA53tc7FlyACQ\n"
+ "pqe4U/GSTyoCUmPvdiiKc2SlM7JpiBtujUfIrIGyoPamsYodtQspdEeGzJaoSTwd\n"
+ "H9OJAmCRYIUrkAyE9XKediKkN7I7goQ0bbEUPMLCBuYGlaLmi6mjsdkXgBYDCfdl\n"
+ "Lp5y93zATlDCNfFtFnpaNsdCiGGRiLQKZOGEfsySa3DSMqXy+CUkv51VVkPf2i9D\n"
+ "Qx6gF4XphsJU9W0S+vjSCAFQ6e6zdAKduVLaTRrw29s11uNGdFebcMMPxGlGsNOd\n"
+ "jQAAAAAAAA==\n"
+ "-----END SIGNED MESSAGE-----\n";
+
namespace
{
@@ -195,6 +227,17 @@ public:
qputenv("TZ", "UTC");
}
+ QByteArray readTestData(const QString &fileName) const
+ {
+ const QString filePath = ":/testdata/formattingtest/"_L1 + fileName;
+ QFile file{filePath};
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Failed to open test data file:" << filePath;
+ return {};
+ }
+ return file.readAll();
+ }
+
QString maskDateAndTime(QString text) const
{
static const QString datePattern = u"[0-9]{1,4}[-/][0-9]{1,2}[-/][0-9]{1,4}"_s;
@@ -386,6 +429,172 @@ private Q_SLOTS:
const auto formatAnyUID = Formatting::prettySignature(verificationResult.signature(0), QString());
QVERIFY(formatAnyUID.contains(secondUID));
}
+
+ void test_prettyDataSignature_data()
+ {
+ QTest::addColumn<Signature::Summary>("sigSummary");
+ QTest::addColumn<gpg_err_code_t>("sigStatus");
+ QTest::addColumn<Signature::Validity>("sigValidity");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("all-good")
+ << static_cast<Signature::Summary>(Signature::Summary::Green | Signature::Summary::Valid) << GPG_ERR_NO_ERROR << Signature::Validity::Full //
+ << u"Signature verification was successful: Data and signature match and the certificate is valid and trusted.<br/>"
+ "Signed by <a href=\"key:27E12CEFBE2E11FAF985106BD24D35D21E3C740D\">Certified Key <[email protected]> (DATE)</a> on DATETIME."_s;
+ QTest::newRow("key-expired")
+ << Signature::Summary::KeyExpired << GPG_ERR_KEY_EXPIRED << Signature::Validity::Unknown
+ << u"The data cannot be trusted. Reason: The signing certificate has expired.<br/>"
+ "Signed by <a href=\"key:972263BC1577E48958A2AF7A6CFC883EEE0918B1\">Expired Key <[email protected]> (DATE)</a> on DATETIME."_s;
+ QTest::newRow("key-not-certified")
+ << Signature::Summary::None << GPG_ERR_NO_ERROR << Signature::Validity::Unknown
+ << u"The data cannot be trusted. Reason: It cannot be verified whether the data originates from the stated source.<br/>"
+ "Signed by <a href=\"key:9152100939FC36332EC5954AD7ADC02ACDFA945A\">Not Certified <[email protected]> (DATE)</a> on DATETIME."_s;
+ QTest::newRow("key-revoked")
+ << Signature::Summary::KeyRevoked << GPG_ERR_CERT_REVOKED << Signature::Validity::Unknown
+ << u"The data cannot be trusted. Reason: The signing certificate has been revoked.<br/>"
+ "Signed by <a href=\"key:BA80E58FB5EC794D6396D47ADABA14732513A6D6\">Revoked Key <[email protected]> (DATE)</a> on DATETIME."_s;
+ QTest::newRow("key-unknown")
+ << Signature::Summary::KeyMissing << GPG_ERR_NO_PUBKEY << Signature::Validity::Unknown
+ << u"The signature cannot be verified because the corresponding certificate is not available. The data cannot be trusted. The signing "
+ "certificate’s fingerprint is <a href=\"certificate:C8C6053CA0018BCB1C0D3C1AF9F33E35E1C16A17\">"
+ "C8C6 053C A001 8BCB 1C0D 3C1A F9F3 3E35 E1C1 6A17</a>."_s;
+ QTest::newRow("signature-bad")
+ << Signature::Summary::Red << GPG_ERR_BAD_SIGNATURE << Signature::Validity::Unknown
+ << u"The data cannot be trusted. Reason: Data and signature do not match.<br/>"
+ "The signature claims to be from <a href=\"key:117C22E18017CB18A67FC3D699954415471E4A5F\">Second UID <[email protected]> (DATE)</a>."_s;
+ QTest::newRow("signature-expired")
+ << Signature::Summary::SigExpired << GPG_ERR_SIG_EXPIRED << Signature::Validity::Unknown
+ << u"The data cannot be trusted. Reason: The signature has expired.<br/>"
+ "Signed by <a href=\"key:9152100939FC36332EC5954AD7ADC02ACDFA945A\">Not Certified <[email protected]> (DATE)</a> on DATETIME."_s;
+ }
+
+ void test_prettyDataSignature()
+ {
+ QFETCH(Signature::Summary, sigSummary);
+ QFETCH(gpg_err_code_t, sigStatus);
+ QFETCH(Signature::Validity, sigValidity);
+ QFETCH(QString, expected);
+ const auto currentDataTag = QString::fromLatin1(QTest::currentDataTag());
+
+ const auto temporaryDir = QTest::qExtractTestData(QStringLiteral("/fixtures/formattingtest"));
+ const auto gnupgHome = CustomGnuPGHome(temporaryDir->path());
+
+ const auto keyCache = KeyCache::instance();
+ QVERIFY(!keyCache->keys().empty());
+
+ const QString signedDataFile = "openpgp-signature-"_L1 + currentDataTag + ".txt"_L1;
+ const QByteArray signature = readTestData(signedDataFile + ".sig"_L1);
+ const QByteArray signedData = readTestData(signedDataFile);
+ const std::unique_ptr<QGpgME::VerifyDetachedJob> verifyJob{QGpgME::openpgp()->verifyDetachedJob()};
+ QByteArray verified;
+
+ const VerificationResult verificationResult = verifyJob->exec(signature, signedData);
+ // qWarning() << QGpgME::toLogString(verificationResult);
+ QVERIFY(!verificationResult.error());
+ QCOMPARE(verificationResult.numSignatures(), 1);
+ const GpgME::Signature sig = verificationResult.signature(0);
+ QCOMPARE(sig.summary(), sigSummary);
+ QCOMPARE(sig.status().code(), sigStatus);
+ QCOMPARE(sig.validity(), sigValidity);
+
+ const QString result = Formatting::prettyDataSignature(verificationResult.signature(0), {});
+ QCOMPARE(maskDateAndTime(result), expected);
+ }
+
+ void test_prettyDataSignature_unknown_smime_key()
+ {
+ const TemporaryGnuPGHome gnupgHome;
+
+ const auto keyCache = KeyCache::instance();
+ QVERIFY(keyCache->keys().empty());
+
+ const QByteArray signedData{opaque_smime_signed_data};
+ const std::unique_ptr<QGpgME::VerifyOpaqueJob> verifyJob{QGpgME::smime()->verifyOpaqueJob()};
+ QByteArray verified;
+
+ const VerificationResult verificationResult = verifyJob->exec(signedData, verified);
+ QVERIFY(!verificationResult.error());
+ QCOMPARE(verificationResult.numSignatures(), 1);
+
+ const QString result = Formatting::prettyDataSignature(verificationResult.signature(0), {});
+ const auto expected = u"The signature cannot be verified because the corresponding certificate is not available. The data cannot be trusted."_s;
+ QCOMPARE(result, expected);
+ }
+
+ void test_prettyDataSignature_devs_data()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.5.2") {
+ QSKIP("needs gpg 2.5.2+ for assuming de-vs compliance");
+ }
+
+ QTest::addColumn<Signature::Summary>("sigSummary");
+ QTest::addColumn<gpg_err_code_t>("sigStatus");
+ QTest::addColumn<Signature::Validity>("sigValidity");
+ QTest::addColumn<bool>("isDeVs");
+ QTest::addColumn<QString>("expected");
+
+ static const auto greenAndValid = static_cast<Signature::Summary>(Signature::Summary::Green | Signature::Summary::Valid);
+ QTest::newRow("all-good-and-compliant") //
+ << greenAndValid << GPG_ERR_NO_ERROR << Signature::Validity::Full << true //
+ << u"Signature verification was successful: Data and signature match and the certificate is valid and trusted.<br/>"
+ "Signed by "
+ "<a href=\"key:16D60818031DB56D03CDAF698A10E5C2C8CD6827\">Certified Key (Compliant) <[email protected]> (DATE)</a>"
+ " on DATETIME.<br/>"
+ "The signature is COMPLIANCE."_s;
+ QTest::newRow("all-good") // but not compliant
+ << greenAndValid << GPG_ERR_NO_ERROR << Signature::Validity::Full << false //
+ << u"Signature verification was successful: Data and signature match and the certificate is valid and trusted.<br/>"
+ "Signed by <a href=\"key:27E12CEFBE2E11FAF985106BD24D35D21E3C740D\">Certified Key <[email protected]> (DATE)</a> on DATETIME.<br/>"
+ "The signature <b>is not</b> COMPLIANCE."_s;
+ }
+
+ void test_prettyDataSignature_devs()
+ {
+ static bool firstCall = true;
+
+ QFETCH(Signature::Summary, sigSummary);
+ QFETCH(gpg_err_code_t, sigStatus);
+ QFETCH(Signature::Validity, sigValidity);
+ QFETCH(bool, isDeVs);
+ QFETCH(QString, expected);
+ const auto currentDataTag = QString::fromLatin1(QTest::currentDataTag());
+
+ EnvironmentVariableOverride envVarOverride{"GNUPG_ASSUME_COMPLIANCE", "de-vs"};
+ Tests::DeVSCompliance::forceUsageOfCompliance(true);
+
+ const auto temporaryDir = QTest::qExtractTestData(QStringLiteral("/fixtures/formattingtest-devs"));
+ const auto gnupgHome = CustomGnuPGHome(temporaryDir->path());
+ if (firstCall) {
+ // ensure that the backend configuration is re-read
+ QGpgME::cryptoConfig()->clear();
+ }
+ QVERIFY(DeVSCompliance::isActive());
+ QVERIFY(DeVSCompliance::isCompliant());
+
+ const auto keyCache = KeyCache::instance();
+ QVERIFY(!keyCache->keys().empty());
+
+ const QString signedDataFile = "openpgp-signature-"_L1 + currentDataTag + ".txt"_L1;
+ const QByteArray signature = readTestData(signedDataFile + ".sig"_L1);
+ const QByteArray signedData = readTestData(signedDataFile);
+ const std::unique_ptr<QGpgME::VerifyDetachedJob> verifyJob{QGpgME::openpgp()->verifyDetachedJob()};
+ QByteArray verified;
+
+ const VerificationResult verificationResult = verifyJob->exec(signature, signedData);
+ // qWarning() << QGpgME::toLogString(verificationResult);
+ QVERIFY(!verificationResult.error());
+ QCOMPARE(verificationResult.numSignatures(), 1);
+ const GpgME::Signature sig = verificationResult.signature(0);
+ QCOMPARE(sig.summary(), sigSummary);
+ QCOMPARE(sig.status().code(), sigStatus);
+ QCOMPARE(sig.validity(), sigValidity);
+ QCOMPARE(sig.isDeVs(), isDeVs);
+
+ const QString result = Formatting::prettyDataSignature(verificationResult.signature(0), {});
+ // replace COMPLIANCE with the actual compliance text which may or may not have a trailing "(beta)"
+ expected.replace(u"COMPLIANCE"_s, DeVSCompliance::name(true));
+ QCOMPARE(maskDateAndTime(result), expected);
+ }
};
QTEST_MAIN(FormattingTest)
diff --git a/autotests/formattingtest.qrc b/autotests/formattingtest.qrc
index e5169ec2..d9ce975e 100644
--- a/autotests/formattingtest.qrc
+++ b/autotests/formattingtest.qrc
@@ -11,5 +11,26 @@ SPDX-License-Identifier: CC0-1.0
<file>fixtures/formattingtest/private-keys-v1.d/6728D547F1B47AB917396DE52D13E7F213F6DE0E.key</file>
<file>fixtures/formattingtest/pubring.kbx</file>
<file>fixtures/formattingtest/trustdb.gpg</file>
+ <file>fixtures/formattingtest-devs/gpg.conf</file>
+ <file>fixtures/formattingtest-devs/private-keys-v1.d/0D012E85DAA3A2E54D3644314F0C6A0791B09409.key</file>
+ <file>fixtures/formattingtest-devs/private-keys-v1.d/3570307CBB71A5963C13EEBD6E1C7F9F624F5011.key</file>
+ <file>fixtures/formattingtest-devs/pubring.kbx</file>
+ <file>fixtures/formattingtest-devs/trustdb.gpg</file>
+ <file>testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-all-good.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-all-good.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-key-expired.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-key-expired.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-key-not-certified.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-key-not-certified.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-key-revoked.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-key-revoked.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-key-unknown.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-key-unknown.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-signature-bad.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-signature-bad.txt.sig</file>
+ <file>testdata/formattingtest/openpgp-signature-signature-expired.txt</file>
+ <file>testdata/formattingtest/openpgp-signature-signature-expired.txt.sig</file>
</qresource>
</RCC>
diff --git a/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt b/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt.sig
new file mode 100644
index 00000000..393dfbe1
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-all-good-and-compliant.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-all-good.txt b/autotests/testdata/formattingtest/openpgp-signature-all-good.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-all-good.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-all-good.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-all-good.txt.sig
new file mode 100644
index 00000000..558ca778
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-all-good.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt b/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt.sig
new file mode 100644
index 00000000..8c11b7cc
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-key-expired.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt b/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt.sig
new file mode 100644
index 00000000..e17315e4
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-key-not-certified.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt b/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt.sig
new file mode 100644
index 00000000..d8024e2c
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-key-revoked.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt b/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt.sig
new file mode 100644
index 00000000..95a6f4a7
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-key-unknown.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt b/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt
new file mode 100644
index 00000000..0bdd8139
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt
@@ -0,0 +1,2 @@
+Sign me!
+!!!This line was added after the file was signed!!!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt.sig
new file mode 100644
index 00000000..6379bac0
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-signature-bad.txt.sig differ
diff --git a/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt b/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt
new file mode 100644
index 00000000..f9655dd0
--- /dev/null
+++ b/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt
@@ -0,0 +1 @@
+Sign me!
diff --git a/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt.sig b/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt.sig
new file mode 100644
index 00000000..9bc9d02e
Binary files /dev/null and b/autotests/testdata/formattingtest/openpgp-signature-signature-expired.txt.sig differ
diff --git a/src/utils/formatting.cpp b/src/utils/formatting.cpp
index 3d0f1fc6..0af5fa20 100644
--- a/src/utils/formatting.cpp
+++ b/src/utils/formatting.cpp
@@ -1519,11 +1519,26 @@ static QString renderKey(const GpgME::Key &key, const GpgME::UserID &uid)
i18nc("User ID (Key ID)", "%1 (%2)", uidString, Formatting::prettyID(key.subkey(0).keyID())));
}
+static QString renderKeyV2(const GpgME::Key &key, const GpgME::UserID &uid)
+{
+ if (key.isNull()) {
+ return i18n("Unknown certificate");
+ }
+ const QString uidString = uid.isNull() ? Formatting::prettyNameAndEMail(key) : Formatting::prettyNameAndEMail(uid);
+ return renderKeyLink(QLatin1StringView(key.primaryFingerprint()),
+ i18nc("User ID (creation date)", "%1 (%2)", uidString, Formatting::creationDateString(key)));
+}
+
static QString renderFingerprintLink(const char *fpr)
{
return u"<a href='certificate:%1'>%2</a>"_s.arg(QString::fromLatin1(fpr), Formatting::prettyID(fpr));
}
+static QString renderFingerprintLinkV2(const char *fpr)
+{
+ return u"<a href=\"certificate:%1\">%2</a>"_s.arg(QString::fromLatin1(fpr), Formatting::prettyID(fpr));
+}
+
static QDateTime signatureCreationTime(const GpgME::Signature &sig)
{
return sig.creationTime() != 0 ? QDateTime::fromSecsSinceEpoch(quint32(sig.creationTime())) : QDateTime();
@@ -1534,6 +1549,30 @@ static QString renderSignatureCreationTime(const QDateTime &dt)
return dt.isValid() ? QLocale().toString(dt, QLocale::ShortFormat) : QString{};
}
+static QString renderSignedByOn(const GpgME::Signature &sig, const GpgME::Key &key, const GpgME::UserID &userID)
+{
+ const QDateTime sigCreationTime = signatureCreationTime(sig);
+ if (sigCreationTime.isValid()) {
+ return i18nc("@info", "Signed by %1 on %2.", renderKeyV2(key, userID), renderSignatureCreationTime(sigCreationTime));
+ } else {
+ return i18nc("@info", "Signed by %1.", renderKeyV2(key, userID));
+ }
+}
+
+static QString renderSignatureCompliance(const GpgME::Signature &sig)
+{
+ if (Kleo::DeVSCompliance::isCompliant() && ((sig.summary() & GpgME::Signature::Valid) || (sig.summary() & GpgME::Signature::Green))) {
+ return QStringLiteral("<br/>")
+ + (sig.isDeVs() ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
+ "The signature is %1.",
+ Kleo::DeVSCompliance::name(true))
+ : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
+ "The signature <b>is not</b> %1.",
+ Kleo::DeVSCompliance::name(true)));
+ }
+ return {};
+}
+
static QString formatSigningInformation(const GpgME::Signature &sig, const GpgME::Key &key, const GpgME::UserID &uid)
{
if (sig.isNull()) {
@@ -1556,15 +1595,7 @@ static QString formatSigningInformation(const GpgME::Signature &sig, const GpgME
text += i18n("Signature created with certificate: %1", renderKey(key, uid));
}
- if (Kleo::DeVSCompliance::isCompliant() && ((sig.summary() & GpgME::Signature::Valid) || (sig.summary() & GpgME::Signature::Green))) {
- text += (QStringLiteral("<br/>")
- + (sig.isDeVs() ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
- "The signature is %1",
- Kleo::DeVSCompliance::name(true))
- : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
- "The signature <b>is not</b> %1.",
- Kleo::DeVSCompliance::name(true))));
- }
+ text += renderSignatureCompliance(sig);
return text;
}
@@ -1744,3 +1775,91 @@ QString Kleo::Formatting::prettySignature(const GpgME::Signature &sig, const QSt
}
return ret;
}
+
+QString Kleo::Formatting::prettyDataSignature(const GpgME::Signature &sig, const QString &sender)
+{
+ if (sig.isNull()) {
+ return QString();
+ }
+
+ const GpgME::Key key = Kleo::KeyCache::instance()->findSigner(sig);
+
+ GpgME::UserID userID;
+ if (!sender.isEmpty()) {
+ userID = findUserIDByMailbox(key, sender);
+ }
+ if (userID.isNull() && !key.isNull()) {
+ userID = key.userID(0);
+ }
+
+ // Valid (implies Green)
+ if ((sig.summary() & GpgME::Signature::Valid)) {
+ return i18nc("@info", "Signature verification was successful: Data and signature match and the certificate is valid and trusted.") + "<br/>"_L1
+ + renderSignedByOn(sig, key, userID) //
+ + renderSignatureCompliance(sig);
+ }
+
+ // Red (means either bad signature or validity "never" for the signing key)
+ if ((sig.summary() & GpgME::Signature::Red)) {
+ const QDateTime sigCreationTime = signatureCreationTime(sig);
+ const QString reason = (sig.status().code() == GPG_ERR_BAD_SIGNATURE) //
+ ? i18nc("@info", "Data and signature do not match.")
+ : i18nc("@info", "The signing certificate must not be trusted."); // happens with TOFU trust model and with failed S/MIME certificate chain auditing
+ QString text = i18nc("@info", "The data cannot be trusted. Reason: %1", reason) + "<br/>"_L1;
+ if (sigCreationTime.isValid()) {
+ text += i18nc("@info", "The signature claims to be from %1 and dated %2.", renderKeyV2(key, userID), renderSignatureCreationTime(sigCreationTime));
+ } else {
+ text += i18nc("@info", "The signature claims to be from %1.", renderKeyV2(key, userID));
+ }
+ return text;
+ }
+
+ // Key missing
+ if ((sig.summary() & GpgME::Signature::KeyMissing)) {
+ QString text = i18nc("@info", "The signature cannot be verified because the corresponding certificate is not available. The data cannot be trusted.");
+ // TODO: Print signing certificate’s issuer and S/N for missing S/MIME certificate once we get this data from gpgsm.
+ if (sig.fingerprint()) {
+ text += u' ';
+ text += i18nc("@info", "The signing certificate’s fingerprint is %1.", renderFingerprintLinkV2(sig.fingerprint()));
+ }
+ return text;
+ }
+
+ // Good signature with some caveats
+ if (sig.status().isSuccess()) {
+ const QString reason = i18nc("@info", "It cannot be verified whether the data originates from the stated source.");
+ return i18nc("@info", "The data cannot be trusted. Reason: %1", reason) + "<br/>"_L1 //
+ + renderSignedByOn(sig, key, userID) //
+ + renderSignatureCompliance(sig);
+ }
+
+ // Expired signature (only occurs for OpenPGP)
+ if (sig.status().code() == GPG_ERR_SIG_EXPIRED) {
+ const QString reason = i18nc("@info", "The signature has expired.");
+ return i18nc("@info", "The data cannot be trusted. Reason: %1", reason) + "<br/>"_L1 //
+ + renderSignedByOn(sig, key, userID) //
+ + renderSignatureCompliance(sig);
+ }
+
+ // Good signature but expired signing key
+ if (sig.status().code() == GPG_ERR_KEY_EXPIRED) {
+ const QString reason = i18nc("@info", "The signing certificate has expired.");
+ return i18nc("@info", "The data cannot be trusted. Reason: %1", reason) + "<br/>"_L1 //
+ + renderSignedByOn(sig, key, userID) //
+ + renderSignatureCompliance(sig);
+ }
+
+ // Good signature but revoked signing key
+ if (sig.status().code() == GPG_ERR_CERT_REVOKED) {
+ const QString reason = i18nc("@info", "The signing certificate has been revoked.");
+ return i18nc("@info", "The data cannot be trusted. Reason: %1", reason) + "<br/>"_L1 //
+ + renderSignedByOn(sig, key, userID);
+ }
+
+ // Catch all fall through
+ QString text = i18n("The signature is invalid: %1", signatureSummaryToString(sig.summary()));
+ if (sig.summary() & GpgME::Signature::SysError) {
+ text += "<br/>"_L1 + i18nc("@info", "Error: %1", Kleo::Formatting::errorAsString(sig.status()));
+ }
+ return text;
+}
diff --git a/src/utils/formatting.h b/src/utils/formatting.h
index 4dc7882e..b19c256c 100644
--- a/src/utils/formatting.h
+++ b/src/utils/formatting.h
@@ -97,6 +97,20 @@ KLEO_EXPORT QString accessibleHexID(const char *id);
*/
KLEO_EXPORT QString prettySignature(const GpgME::Signature &signature, const QString &sender);
+/**
+ * Formats a signature from a VerificationResult.
+ *
+ * The texts are suited for signatures of files or other data, e.g. those made with Kleopatra.
+ * They are less suited for signatures of emails.
+ *
+ * @param signature The signature to display.
+ * @param sender The sender of the signature, if multiple UserIds are found, this will be the displayed one otherwise the first non empty UserID will be
+ * displayed.
+ *
+ * @note The resulting string will contains links to the key in the following format "key:<fingerprint>".
+ */
+KLEO_EXPORT QString prettyDataSignature(const GpgME::Signature &signature, const QString &sender);
+
// clang-format off
enum ToolTipOption {
KeyID = 0x001,