diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index a0882d7a8..1b9070b8a 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,29 +1,36 @@ remove_definitions(-DQT_NO_CAST_FROM_ASCII) include(ECMAddTests) find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG QUIET) if(NOT Qt5Test_FOUND) message(STATUS "Qt5Test not found, autotests will not be built.") return() endif() ecm_add_test( flatkeylistmodeltest.cpp abstractkeylistmodeltest.cpp TEST_NAME flatkeylistmodeltest LINK_LIBRARIES KF5::Libkleo Qt5::Test ) ecm_add_test( hierarchicalkeylistmodeltest.cpp abstractkeylistmodeltest.cpp TEST_NAME hierarchicalkeylistmodeltest LINK_LIBRARIES KF5::Libkleo Qt5::Test ) +ecm_add_test( + keyresolvertest.cpp + keyresolvertest.qrc + TEST_NAME keyresolvertest + LINK_LIBRARIES KF5::Libkleo Qt5::Widgets Qt5::Test +) + ecm_add_tests( newkeyapprovaldialogtest.cpp LINK_LIBRARIES KF5::Libkleo Qt5::Widgets Qt5::Test ) diff --git a/autotests/fixtures/keyresolvertest/.gitignore b/autotests/fixtures/keyresolvertest/.gitignore new file mode 100644 index 000000000..895a1a3c2 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/.gitignore @@ -0,0 +1,3 @@ +openpgp-revocs.d/ +random_seed +tofu.db diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/029551BEA335EC0F84109F1EDD23E0FA44FEB336.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/029551BEA335EC0F84109F1EDD23E0FA44FEB336.key new file mode 100644 index 000000000..598738ddb --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/029551BEA335EC0F84109F1EDD23E0FA44FEB336.key @@ -0,0 +1,5 @@ +Created: 20210322T134216 +Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q + #402338211D73F530D81F8FD2D906EEC3E127C549A031E3514EF408F26119FC3BB0#) + (d #89520701F0C40E2FCE89DF7378000358557BAF9765588464D2A434C60577636E#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/068B3A87EB6029DC958371D42A8CF22913F792BA.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/068B3A87EB6029DC958371D42A8CF22913F792BA.key new file mode 100644 index 000000000..e2f6aa6ea --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/068B3A87EB6029DC958371D42A8CF22913F792BA.key @@ -0,0 +1,32 @@ +Created: 20210322T135004 +Key: (protected-private-key (rsa (n #00D93727139ED5044AEEB02BD9D2096F2C + 76BBEBFB7E64E51592C81D11A44AE96B14E6DD2F333ABA41FCD24860932859CBEFA0C5 + FA22EC3F5085CB0F7BC1D61F1C8FA1CADC04A916ADECB576250E02D6FB0FB8AA8C6347 + 08B2ABDFDB0059D634B045AADF69E20E3E97A13110CB6436CA0A1881070ED14D2EC482 + 09BEAB0DE56B6DE178236AAA0314A7474EC85314857856633BC572A864EE2571C157B8 + B944B5ECB3C85B5CEEBB4FF42928DA57DA45658D9268DED792B818F0CF83ECB5ED97AC + DB5A10F1F1E800565D70D5FE175C93EF3E4468765015DEBB768A5F53C061756F128181 + D6DA2B08ED396E7765C58659B4EF37173CE33E6CD7DD0BAD2793C4F88B75#)(e + #010001#)(protected openpgp-s2k3-ocb-aes ((sha1 "\fT5gÃÈÆ?" + "53686272")#D98B1FCB502A730F10473897#)#146BB2167B12E4703EDD7F8A7C5F63 + C68DC63536E6C98DCB8A16BC1D948F366D74F9B991C6050B79BC521B767E9A67BB095E + C117900C945DAC62EC4913DAFEC40D1E2B6C698F0028981D9E927D2BC0D84305DBA84B + 480BE98E7B438BB304A96596A21B4FDC7A2BC65E8A0428D2A48D99D3845FE4E31E5B81 + 655F89F551873526B1FF4BB3DA0DA81959F64D4730E09DBF3A20D739AF09AEF8D39E70 + 51D422A0692DF157D14879D66BF5A6463EC9CF1249B2382D954CC1C2C7944C22DC3E06 + 7E7752D1D38CAE872AF357373FA69279B392EFC3134ADA09D3DD18B38D1AFABDD434AD + E6E8C83FE4A0B7451591C785983D1FCB949B4C1070D6DF84B34241E08E75549FC4C3E6 + F983D729BC5F3577830EAD736EA8A8A05ED2E95D855C4083DC6396B252CA23C807D0AC + 66AD91EE4003D0EBF979A316663A14B3D175D5E270308C68E0E708E7813A070ECC6404 + 688E9944EC055669D7B1CC07B2A50096C515B6F8E9EB8A928DBAB0037056062D816410 + 100EF8A74B01D988D51D917D758185C51E423B49E23545A959A8E9678265ADAFFB0670 + 4C168C384280ADC4990356A7EF01DD0AC0FACADB447F57AD7CF3F71DA694A1CB23E9D1 + DF514921D0B903BEA56EC990F2B4A351B172671873D4CB375800E4E41DC5FD889B9CBC + DC868AEE0298C07BA5E1D0B88F4808014D743E138B883905634EB0A1184ACA435EFA4E + 7152C9DA0D87E1B37255AFF2B0F44E73ACB3690BD0A54469C6F27A0FAD8C8D6D36E143 + EB44742F94DC0B5974443967434CEAFF0832D922EA3CDE600459297DCE28EEBB833A66 + 1E31140A826561F9713DD3BF0E4B5A82A69A89F1A98D69F06DC9719520F714FE7D008A + F0D3307B857B39484C0AEB602B9C61D9A5844A0AD9C166C0B6E9626938F13F93A9FC87 + A8D4F0E06F919D16E0D4ABB252AB729E217619AD33D5644A7803CBFB2D29C87BB2BA5F + 12F0850DFD2BEE9FAB592A3529DDEE9E9A4D#)(protected-at + "20210322T135004"))) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/07E5EE9F946A1760EC7E3DEC3E8665415BF8E5F0.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/07E5EE9F946A1760EC7E3DEC3E8665415BF8E5F0.key new file mode 100644 index 000000000..479c07075 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/07E5EE9F946A1760EC7E3DEC3E8665415BF8E5F0.key @@ -0,0 +1,5 @@ +Created: 20210322T134145 +Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q + #400832EBDB9C115F9295D28F2C485857D039F96E713DB82A7938812598594C7B84#) + (d #5EE2CD85C4E935B6C966526D0ED6B6A75B68DA8F8A97FE700A779A5F1DDDCC81#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/0B767151C33FEE7708F7035860A4D2025C801000.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/0B767151C33FEE7708F7035860A4D2025C801000.key new file mode 100644 index 000000000..39be69f7b --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/0B767151C33FEE7708F7035860A4D2025C801000.key @@ -0,0 +1,32 @@ +Created: 20210322T134956 +Key: (protected-private-key (rsa (n #00D787B9940C8083BA526A58C9CB55FA34 + 9BD8267C30D1FA6D116DBEE5CDC1BD21B27D54EF5AEBE253B64A3CA518375716B2A48E + DF23A737A227251802AE43BB1839ADA0443F6EFB02040D21D0C753B1B3581F469B2BCD + 22FBBF7A7A108E56CE80ECC85D2CD8A7158903887E8AEF0D3E8BB2524752F8D5CDB285 + EFAA90EBA0E9CCB039DCFBC7AD3B618047077599E28A9424DBF20DC8212B57E7F0906A + 0AB48678462C1FEBA6E5B0B1DE9902F52C56CB46AFCF8BCACC61D4891424C59FF04514 + B0E36BD14A45E1982DF6A480649BF4FAF41759B83624909DE64CA0CF478CBEC6BB389A + 128D70DE51564BCB0F7EF2D89546E7FBB99DF66985B06BFF8DC811B67BC5#)(e + #010001#)(protected openpgp-s2k3-ocb-aes ((sha1 #1FF718CDDA024F83# + "53686272")#F8F33DD09D5D50563E0940D7#)#987A0F3D878875F6F9E1B62237DBC1 + D888212F697E9AAB7F5177B2F832086181B2571F151FB2461B13C5EFEC499707E7B1A8 + C380BD05DCFA2D899056ECCF25B2F32D167C0B79C7390CB2D94637701ACDE7B1D67C3D + AE479504319BD6844C1B2671263A676F862B5A9636FC56C0EF5DCDDB534F985A8B705E + E1D6BEC02F1CBBB197E2953666FE802918E9888323947B8677CF5E67F426D41F0C10E5 + 9699C1FE5A1D6F9A242C6D26C7AACB86BF54B163CE9189A961093E49665B9C2603BD4E + 08225A58378E88420E6EB366B15025414010D2FD235CC935A76661DEF928E8110FF07D + 9B0CC1E1133D1D7686AFD24C85487363F63C7B7816B887672F74922590B54306DE2F15 + C29F3CED3B3C64E641F30207590DD5DE1853141493115CD946E010A9E8E55E9D4B7C6B + 438B0C78835807FE7309AC8A8BF17E9951BA9707575D7CDDADA684DECD446D9DF4263E + 5803716FAF31B279FB8214209458EE055A04247C21F5298C73C6037AECA2624071F0AE + A8817979908EB4CA190D069F65B214CC6ACA88A48D0C09874644E13904C6A53948F601 + 77D9C15C450CEFA75E1AC7E851239E1374012E89B21F6FF9B038F7034E210D989F2462 + 69E914A75AE3449C6C2B95E1CE5C3F956322074AF0FB78ADDDB1FACDB7D0A6641EE436 + 5BE00472B246431A25018E5D6DAA8CBF419D7CDAE1997DA67715A8BC403EB7EFA81C7E + 0C8018FA9156B2B5BA310BF5C8AF5AFF4E0F7F3D80D25855D4F0AB571580D66297C682 + D4913E9B51F1B1CFE1E8D4CAEFB42632728EDF802C4666200E334EBE590577D9D866EC + D7B972D8DFE348C1E47C5F71D1324AC5064217709319487255E9C231A06B69F39DD107 + 47322B6926F8CEAFE16F47ECDA4177B6FB7319B1E14BDBAA8AAF349C824D9C78932EB4 + 8C2201D7698F798D1812D53FAB7F4DC967C64DF5AE582EF218BEE1BCF0C1832A5E823E + 3BA133AD82E86270320619686CCD0B915C8C#)(protected-at + "20210322T134956"))) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/2B38646AEC0F0D6AE2EEF714963722C0E58BF95F.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/2B38646AEC0F0D6AE2EEF714963722C0E58BF95F.key new file mode 100644 index 000000000..d3d268da7 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/2B38646AEC0F0D6AE2EEF714963722C0E58BF95F.key @@ -0,0 +1,32 @@ +Created: 20210322T135027 +Key: (protected-private-key (rsa (n #00CB691B6AF9496B3B30D1262C5924A5F4 + 75AB3A0BBBDED7283254DAAF66AEAA20D3B142883959E1D382D7D9480A79B6070CAF44 + E60861A0939C191302B0BBF9837821B141EBEAF8DCD17C074B13A5459D90E7BD8F3E82 + BD98F542CC76E4F8038726C1671023CF49CBCEAE937DCCA14A2CDD8C12EA1269898229 + 4108D76E6432D17AA5CB50C2D94F57ED312B1B8C352873E543867E019C93AC26EADB8F + 1047939C2C8BF7C9A5FD42F7BDAFB48ED267F729980B35D8448A64B7BAD0FD8885041A + 6728AAAF1155D328F01F11ADBE0FBC591D08723E5B0270FC703DE3B075D072FEDC420C + FE8901339C133E333A697424A8F530C4A6A79CA9B0734E066068915F4E07#)(e + #010001#)(protected openpgp-s2k3-ocb-aes ((sha1 #E5CD258D08FA0B17# + "53686272")#E359E322AE99FE55AB12C20B#)#12425AFB59FFBD153A29D61B063756 + CA14F2FA802485A108C01BECCD21DDFE2192E4B14ECDF644D229AF6427644B86493544 + D55CFFE2E992EEC419EFCCC641A0B4431D9EB3090C4034A9F9E51486E30D1892DE64F8 + EB365EC0D65C245E3030A9D9724D3F26A7DE980CF1074D1574D3B982C6C4FDEC4C20CA + 93CF315325210E00B9F6916AF4175A100D8D67A94833757470C8EACA75FDF611B81245 + 0B8F0A8E8BA6E7DFA4BA937B750C5E5F863AB28612D50A330450D6EB7534AEF23BCD5C + 7D9E74D7B71B1201921909295FC30F82512F6D610F267A5F971ABE5D156114B1A4A2E8 + 945A8E19CBA734EDCD461E4D593BEC3C01B068041079233FF3F63A919030AE8C32ED4E + 4FE58DC350D32ADE953C0A6481DAC100ECEF27FE6BB96AAF96B2D49541825A4266A85F + 6CB9E8E004E7E6C87A3980D0EB513ED06A622C8B14EEC2C1DF473EB5BF133B29DA54C9 + 22060A4369E17288D8048B5725A413548541BF4EB656843C2C9B2120CD1C49B5DAA4FB + 6892E9795F06508303539A5F345584E0E44A7B323CCEF80C6CFC0CFE3342E929344986 + 8D84B82F7CB2B005B72C1A2A85CB13ADDDFE00207F63B306464539D1CEE017C9E7F9C1 + C4DD789F98F5306975015076DC752840F71B654A6F23ED0BFA1F5D06F1F760B97E30FE + 89560A8BE3D5BFB76B3476D9B58D5BA61C7F9145395CD248905206958D4579AD1444F9 + 591CE5ADBD61330D3D5883293AD142CB8D5C01AF30B0F83AE3C90042848BF0ABF6A937 + A8D000DA8ECEA9037E31BB13090C498A148CD8E032649A96E4D9A0E23360FDC52D4E00 + CA020455B3D117B9D3DA198D34C0C9F7C445436E7CD248EE4C4B3F04B5E0A98DA0DF08 + E946494D683E0BDB25E49FAAD397B7B76BF855FED0D7ED72E1747C331ED923A2C76B11 + 77DE39C6AF783A61CD46CCD73DC529EC30176C7F3900410944240B91C492C8BAAF3CF6 + 55B7848230F5A76B7AF90E44AC825C4645B0#)(protected-at + "20210322T135027"))) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/4205C2F4EC7F5C7FBD175C5025A74E374E768B17.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/4205C2F4EC7F5C7FBD175C5025A74E374E768B17.key new file mode 100644 index 000000000..d703bc8e3 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/4205C2F4EC7F5C7FBD175C5025A74E374E768B17.key @@ -0,0 +1,5 @@ +Created: 20210322T134216 +Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q + #40E78024E41F2911080AE20FD6B04B2BBD598C3EBE6197C9D60ABECFB216D74375#) + (d #69297679FA3D383441D41FD08A4DCD39B8CC9E68985FDD39E33F8DF9DCF15DB0#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/8CD2635EB4B7766E0C174E62853FCE072795D304.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/8CD2635EB4B7766E0C174E62853FCE072795D304.key new file mode 100644 index 000000000..880bd30c3 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/8CD2635EB4B7766E0C174E62853FCE072795D304.key @@ -0,0 +1,5 @@ +Created: 20210322T134220 +Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q + #4006C1724E47BD4F9F9EB41EEE699D8FDA330C632C4E6214ED831388A4ED556003#) + (d #7116799C23A8F148750B68B24DE6857C24BCC8F43046A8C532A51AB03DB065C0#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/93FBC8415935DD866AEAE179D70A58B1BEE7EA85.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/93FBC8415935DD866AEAE179D70A58B1BEE7EA85.key new file mode 100644 index 000000000..0109f0649 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/93FBC8415935DD866AEAE179D70A58B1BEE7EA85.key @@ -0,0 +1,5 @@ +Created: 20210322T134151 +Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q + #4023F662E532E75530DE11A91FCF0E3012E3C6DDC7D7AC9D66C9BD2AFDB1C32D2E#) + (d #77E8EFAA560CB50690FE40582036AE44C913D2F9BF4DD549B144D97EE2371B00#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/9A54238A5B7D396D48A584255A1DE5622FBF8B99.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/9A54238A5B7D396D48A584255A1DE5622FBF8B99.key new file mode 100644 index 000000000..7e49ff599 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/9A54238A5B7D396D48A584255A1DE5622FBF8B99.key @@ -0,0 +1,5 @@ +Created: 20210322T134157 +Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q + #40DD580043C3B59DF4D899B597496151AC7E0182C73C83681447972B0FEFE7676D#) + (d #7144E019242E5312B714CECFDBB47A9A02AD0BAED257CBAFD6E1B071838020C0#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/A4E6D1CEBA63087E47B84863BF16D8E81F0B7629.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/A4E6D1CEBA63087E47B84863BF16D8E81F0B7629.key new file mode 100644 index 000000000..05933f74f --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/A4E6D1CEBA63087E47B84863BF16D8E81F0B7629.key @@ -0,0 +1,5 @@ +Created: 20210322T134151 +Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q + #4010C64C4A284C4B81CA883590BF10E986F3D3C1D5BF45FAC60C8728B565753342#) + (d #E5ADD71A3A0B6C993A012EF970D55DA7EB87B78DA6CAF882CC94CF70EF9E6AFE#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/B185B49FC722A9C92F8C2C30438BA225363F0A6B.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/B185B49FC722A9C92F8C2C30438BA225363F0A6B.key new file mode 100644 index 000000000..92f45a577 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/B185B49FC722A9C92F8C2C30438BA225363F0A6B.key @@ -0,0 +1,5 @@ +Created: 20210322T134220 +Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q + #40CD91F555AD506E9564604BD0F20246D4E279894F370DACAD05F578016E0FC4E2#) + (d #3D5FE89878F6133E58EAC83EFBBFF6DFBA9382DF7CDA6F5BAE05185AD0D1C7AD#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/B9E7A40AA2CE1512A3270374D05AB0A74F98E54E.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/B9E7A40AA2CE1512A3270374D05AB0A74F98E54E.key new file mode 100644 index 000000000..71d91e008 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/B9E7A40AA2CE1512A3270374D05AB0A74F98E54E.key @@ -0,0 +1,5 @@ +Created: 20210322T134157 +Key: (private-key (ecc (curve Ed25519)(flags eddsa)(q + #400480F599560A51C9E0232E151D77339E98EEA9FE1FC141C96D0D42042C391269#) + (d #F665058FB22AD3B4B5A9C804B942DEC97C4834C45017917D9FCD0029701A7AA2#) + )) diff --git a/autotests/fixtures/keyresolvertest/private-keys-v1.d/F769B16A6206E8F17D0AFB99EDB44BE813943A2C.key b/autotests/fixtures/keyresolvertest/private-keys-v1.d/F769B16A6206E8F17D0AFB99EDB44BE813943A2C.key new file mode 100644 index 000000000..46df225b7 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/private-keys-v1.d/F769B16A6206E8F17D0AFB99EDB44BE813943A2C.key @@ -0,0 +1,5 @@ +Created: 20210322T134145 +Key: (private-key (ecc (curve Curve25519)(flags djb-tweak)(q + #40B8CCC2EFFDEF6E956DD72BB5D8A0DEE5890D7600263396F6D68356274C3C107C#) + (d #6CB1D7A33CE014ABCEFFC57BD3D580056D14E0821468009066635E4D40068550#) + )) diff --git a/autotests/fixtures/keyresolvertest/pubring.kbx b/autotests/fixtures/keyresolvertest/pubring.kbx new file mode 100644 index 000000000..ee1ac71e3 Binary files /dev/null and b/autotests/fixtures/keyresolvertest/pubring.kbx differ diff --git a/autotests/fixtures/keyresolvertest/readme.md b/autotests/fixtures/keyresolvertest/readme.md new file mode 100644 index 000000000..233c86c5f --- /dev/null +++ b/autotests/fixtures/keyresolvertest/readme.md @@ -0,0 +1,118 @@ +# Fixture for KeyResolverTest + +## Setup + +Set the `GNUPGHOME` environment variable to this folder: +``` +export GNUPGHOME=$(pwd) +``` + +## Generate OpenPGP test keys + +Note: gpg 2.3 is needed for the --no-auto-trust-new-key option. + +``` +# Create an ultimately trusted CA key +gpg --quick-gen-key --batch --pinentry-mode loopback --passphrase "" "Ultimately trusted CA " default default never + +# Create a fully trusted CA key +gpg --quick-gen-key --batch --pinentry-mode loopback --passphrase "" "Fully trusted CA " default default never +gpg --edit-key --command-fd 0 ca-full@example.net <" default default never +gpg --edit-key --command-fd 0 ca-marginal@example.net <" default default never +gpg --delete-secret-keys --batch --yes $(gpg -K --batch --with-colons "Untrusted OpenPGP 1 " | grep fpr | head -1 | cut -d ':' -f 10) +gpg --edit-key --command-fd 0 "Untrusted OpenPGP 1 " <" default default never +gpg --delete-secret-keys --batch --yes $(gpg -K --batch --with-colons "Untrusted OpenPGP 2 " | grep fpr | head -1 | cut -d ':' -f 10) +gpg --edit-key --command-fd 0 "Untrusted OpenPGP 2 " <" default default never +gpg --delete-secret-keys --batch --yes $(gpg -K --batch --with-colons untrusted-mixed@example.net | grep fpr | head -1 | cut -d ':' -f 10) +gpg --edit-key --command-fd 0 untrusted-mixed@example.net <" default default seconds=1 +gpg --delete-secret-keys --batch --yes $(gpg -K --batch --with-colons expired@example.net | grep fpr | head -1 | cut -d ':' -f 10) +``` + +## Generate S/MIME test keys + +``` +gpgsm --gen-key --batch --pinentry-mode loopback --passphrase "" <>trustlist.txt + +gpgsm --gen-key --batch --pinentry-mode loopback --passphrase "" <>trustlist.txt + +gpgsm --gen-key --batch --pinentry-mode loopback --passphrase "" <>trustlist.txt +``` diff --git a/autotests/fixtures/keyresolvertest/trustdb.gpg b/autotests/fixtures/keyresolvertest/trustdb.gpg new file mode 100644 index 000000000..10aa26f01 Binary files /dev/null and b/autotests/fixtures/keyresolvertest/trustdb.gpg differ diff --git a/autotests/fixtures/keyresolvertest/trustlist.txt b/autotests/fixtures/keyresolvertest/trustlist.txt new file mode 100644 index 000000000..1e19e32d9 --- /dev/null +++ b/autotests/fixtures/keyresolvertest/trustlist.txt @@ -0,0 +1,3 @@ +60:E1:96:4D:9C:EA:44:8E:76:E7:66:42:47:3D:56:7F:FE:95:8E:8A S relax +06:A2:67:BE:B6:04:6A:13:DC:D2:26:56:A6:F4:9D:8B:6E:B3:7A:16 S relax +B8:26:00:8F:4F:5E:8A:86:E3:8A:CD:45:AF:FC:81:AD:01:36:BD:A0 S relax diff --git a/autotests/keyresolvertest.cpp b/autotests/keyresolvertest.cpp new file mode 100644 index 000000000..dd13c7fbb --- /dev/null +++ b/autotests/keyresolvertest.cpp @@ -0,0 +1,127 @@ +/* + autotests/keyresolvertest.cpp + + This file is part of libkleopatra's test suite. + SPDX-FileCopyrightText: 2021 g10 Code GmbH + SPDX-FileContributor: Ingo Klöcker + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace Kleo; +using namespace GpgME; + +class KeyResolverTest: public QObject +{ + Q_OBJECT +private Q_SLOTS: + void init() + { + mGnupgHome = QTest::qExtractTestData("/fixtures/keyresolvertest"); + qputenv("GNUPGHOME", mGnupgHome->path().toLocal8Bit()); + qDebug() << "Using GNUPGHOME" << qgetenv("GNUPGHOME"); + + // hold a reference to the key cache to avoid rebuilding while the test is running + mKeyCache = KeyCache::instance(); + } + + void cleanup() + { + mKeysResolvedSpy.reset(); + + // verify that nobody else holds a reference to the key cache + QVERIFY(mKeyCache.use_count() == 1); + mKeyCache.reset(); + + mGnupgHome.reset(); + } + + void test_verify_test_keys() + { + { + const auto keys = KeyCache::instance()->findByEMailAddress("sender-mixed@example.net"); + QCOMPARE(keys.size(), 2); + QVERIFY((keys[0].protocol() == OpenPGP && keys[1].protocol() == CMS) || + (keys[1].protocol() == OpenPGP && keys[0].protocol() == CMS)); + QVERIFY(keys[0].hasSecret() && keys[0].canEncrypt() && keys[0].canSign()); + QCOMPARE(keys[0].userID(0).validity(), UserID::Ultimate); + QVERIFY(keys[1].hasSecret() && keys[1].canEncrypt() && keys[1].canSign()); + QCOMPARE(keys[1].userID(0).validity(), UserID::Ultimate); + } + { + const auto keys = KeyCache::instance()->findByEMailAddress("sender-openpgp@example.net"); + QCOMPARE(keys.size(), 1); + QVERIFY(keys[0].protocol() == OpenPGP); + QVERIFY(keys[0].hasSecret() && keys[0].canEncrypt() && keys[0].canSign()); + QCOMPARE(keys[0].userID(0).validity(), UserID::Ultimate); + } + { + const auto keys = KeyCache::instance()->findByEMailAddress("prefer-openpgp@example.net"); + QCOMPARE(keys.size(), 1); + QVERIFY(keys[0].protocol() == OpenPGP); + QVERIFY(keys[0].canEncrypt()); + QCOMPARE(keys[0].userID(0).validity(), UserID::Full); + } + { + const auto keys = KeyCache::instance()->findByEMailAddress("prefer-smime@example.net"); + QCOMPARE(keys.size(), 2); + const Key openpgp = keys[0].protocol() == OpenPGP ? keys[0] : keys[1]; + QVERIFY(openpgp.protocol() == OpenPGP); + QVERIFY(openpgp.canEncrypt()); + QCOMPARE(openpgp.userID(0).validity(), UserID::Marginal); + const Key smime = keys[0].protocol() == CMS ? keys[0] : keys[1]; + QVERIFY(smime.protocol() == CMS); + QVERIFY(smime.canEncrypt()); + QVERIFY(smime.userID(0).validity() >= UserID::Full); + } + } + + void test_openpgp_is_preferred_if_openpgp_only_and_smime_only_are_both_possible() + { + KeyResolver resolver(/*encrypt=*/ true, /*sign=*/ true); + resolver.setSender(QStringLiteral("sender-mixed@example.net")); + spyOnKeysResolvedSignal(&resolver); + + resolver.start(/*showApproval=*/ false); + + verifyKeysResolvedSignalEmittedWith(/*success=*/ true, /*sendUnencrypted=*/ false); + QCOMPARE(resolver.signingKeys().value(OpenPGP).size(), 1); + QCOMPARE(resolver.signingKeys().value(CMS).size(), 0); + QCOMPARE(resolver.encryptionKeys().value(OpenPGP).size(), 1); + QCOMPARE(resolver.encryptionKeys().value(OpenPGP).value("sender-mixed@example.net").size(), 1); + QCOMPARE(resolver.encryptionKeys().value(CMS).size(), 0); + } + + void spyOnKeysResolvedSignal(KeyResolver *resolver) + { + mKeysResolvedSpy = std::make_unique(resolver, &KeyResolver::keysResolved); + QVERIFY(mKeysResolvedSpy->isValid()); + } + + void verifyKeysResolvedSignalEmittedWith(bool success, bool sendUnencrypted) + { + QCOMPARE(mKeysResolvedSpy->count(), 1); + const QList arguments = mKeysResolvedSpy->takeFirst(); + QCOMPARE(arguments.at(0).toBool(), success); + QCOMPARE(arguments.at(1).toBool(), sendUnencrypted); + } + +private: + QSharedPointer mGnupgHome; + std::shared_ptr mKeyCache; + std::unique_ptr mKeysResolvedSpy; +}; + +QTEST_MAIN(KeyResolverTest) +#include "keyresolvertest.moc" diff --git a/autotests/keyresolvertest.qrc b/autotests/keyresolvertest.qrc new file mode 100644 index 000000000..6a09bebdd --- /dev/null +++ b/autotests/keyresolvertest.qrc @@ -0,0 +1,21 @@ + + + + fixtures/keyresolvertest/private-keys-v1.d/F769B16A6206E8F17D0AFB99EDB44BE813943A2C.key + fixtures/keyresolvertest/private-keys-v1.d/07E5EE9F946A1760EC7E3DEC3E8665415BF8E5F0.key + fixtures/keyresolvertest/private-keys-v1.d/A4E6D1CEBA63087E47B84863BF16D8E81F0B7629.key + fixtures/keyresolvertest/private-keys-v1.d/93FBC8415935DD866AEAE179D70A58B1BEE7EA85.key + fixtures/keyresolvertest/private-keys-v1.d/B9E7A40AA2CE1512A3270374D05AB0A74F98E54E.key + fixtures/keyresolvertest/private-keys-v1.d/9A54238A5B7D396D48A584255A1DE5622FBF8B99.key + fixtures/keyresolvertest/private-keys-v1.d/029551BEA335EC0F84109F1EDD23E0FA44FEB336.key + fixtures/keyresolvertest/private-keys-v1.d/4205C2F4EC7F5C7FBD175C5025A74E374E768B17.key + fixtures/keyresolvertest/private-keys-v1.d/B185B49FC722A9C92F8C2C30438BA225363F0A6B.key + fixtures/keyresolvertest/private-keys-v1.d/8CD2635EB4B7766E0C174E62853FCE072795D304.key + fixtures/keyresolvertest/private-keys-v1.d/0B767151C33FEE7708F7035860A4D2025C801000.key + fixtures/keyresolvertest/private-keys-v1.d/068B3A87EB6029DC958371D42A8CF22913F792BA.key + fixtures/keyresolvertest/private-keys-v1.d/2B38646AEC0F0D6AE2EEF714963722C0E58BF95F.key + fixtures/keyresolvertest/pubring.kbx + fixtures/keyresolvertest/trustdb.gpg + fixtures/keyresolvertest/trustlist.txt + + diff --git a/src/kleo/keyresolver.cpp b/src/kleo/keyresolver.cpp index 19611f6cd..eb0f9e09e 100644 --- a/src/kleo/keyresolver.cpp +++ b/src/kleo/keyresolver.cpp @@ -1,592 +1,591 @@ /* -*- c++ -*- keyresolver.cpp This file is part of libkleopatra, the KDE keymanagement library SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2018 Intevation GmbH 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 "keyresolver.h" #include "models/keycache.h" #include "ui/newkeyapprovaldialog.h" #include "utils/formatting.h" #include #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 KeyResolver::Private { public: Private(KeyResolver* qq, bool enc, bool sig, Protocol fmt, bool allowMixed) : q(qq), mFormat(fmt), mEncrypt(enc), mSign(sig), mAllowMixed(allowMixed), mCache(KeyCache::instance()), mDialogWindowFlags(Qt::WindowFlags()), mPreferredProtocol(UnknownProtocol), mMinimumValidity(UserID::Marginal), mCompliance(Formatting::complianceMode()) { } ~Private() = default; bool 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 isAcceptableEncryptionKey(const Key &key, const QString &address = QString()) { 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 addRecpients (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 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 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 setSigningKeys(const std::vector &keys) { if (mSign) { for (const auto &key: keys) { 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 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 showApprovalDialog(QWidget *parent) { QMap > resolvedSig; QStringList unresolvedSig; bool pgpOnly = mUnresolvedPGP.empty() && (!mSign || mSigKeys.contains(OpenPGP)); bool cmsOnly = mUnresolvedCMS.empty() && (!mSign || mSigKeys.contains(CMS)); // First handle the signing keys if (mSign) { if (mSigKeys.empty()) { unresolvedSig << mSender; } else { std::vector resolvedSigKeys; for (const auto &keys: qAsConst(mSigKeys)) { for (const auto &key: keys) { resolvedSigKeys.push_back(key); } } resolvedSig.insert(mSender, resolvedSigKeys); } } // Now build the encryption keys QMap > resolvedRecp; QStringList unresolvedRecp; if (mEncrypt) { // Use all unresolved recipients. if (!cmsOnly && !pgpOnly) { if (mFormat == UnknownProtocol) { // In Auto Format we can now remove recipients that could // be resolved either through CMS or PGP for (const auto &addr: qAsConst(mUnresolvedPGP)) { if (mUnresolvedCMS.contains(addr)) { unresolvedRecp << addr; } } } else if (mFormat == OpenPGP) { unresolvedRecp = mUnresolvedPGP; } else if (mFormat == CMS) { unresolvedRecp = mUnresolvedCMS; } } // Now Map all resolved encryption keys regardless of the format. for (const auto &map: mEncKeys.values()) { // Foreach format for (const auto &addr: map.keys()) { // Foreach sender if (!resolvedRecp.contains(addr) || !resolvedRecp[addr].size()) { resolvedRecp.insert(addr, map[addr]); } else { std::vector merged = resolvedRecp[addr]; // Add without duplication for (const auto &k: map[addr]) { const auto it = std::find_if (merged.begin(), merged.end(), [k] (const Key &y) { return (k.primaryFingerprint() && y.primaryFingerprint() && !strcmp (k.primaryFingerprint(), y.primaryFingerprint())); }); if (it == merged.end()) { merged.push_back(k); } } resolvedRecp[addr] = merged; } } } } // Do we force the protocol? Protocol forcedProto = mFormat; // Start with the protocol for which every keys could be found. Protocol presetProtocol; if (mPreferredProtocol == CMS && cmsOnly) { presetProtocol = CMS; } else { presetProtocol = pgpOnly ? OpenPGP : cmsOnly ? CMS : mPreferredProtocol; } mDialog = std::shared_ptr(new NewKeyApprovalDialog(resolvedSig, resolvedRecp, unresolvedSig, unresolvedRecp, mSender, mAllowMixed, forcedProto, presetProtocol, parent, mDialogWindowFlags)); connect (mDialog.get(), &QDialog::accepted, q, [this] () { dialogAccepted(); }); connect (mDialog.get(), &QDialog::rejected, q, [this] () { Q_EMIT q->keysResolved(false, false);} ); mDialog->open(); } void dialogAccepted() { // Update keymaps accordingly mSigKeys.clear(); for (const auto &key: mDialog->signingKeys()) { if (!mSigKeys.contains(key.protocol())) { mSigKeys.insert(key.protocol(), std::vector()); } mSigKeys[key.protocol()].push_back(key); } const auto &encMap = mDialog->encryptionKeys(); // First we clear the Any Maps and fill them with // the results of the dialog. Then we use the sender // address to determine if a keys in the specific // maps need updating. mEncKeys.remove(OpenPGP); mEncKeys.remove(CMS); bool isUnresolved = false; for (const auto &addr: encMap.keys()) { for (const auto &key: encMap[addr]) { if (key.isNull()) { isUnresolved = true; } if (!mEncKeys.contains(key.protocol())) { mEncKeys.insert(key.protocol(), QMap >()); } if (!mEncKeys[key.protocol()].contains(addr)) { mEncKeys[key.protocol()].insert(addr, std::vector()); } qCDebug (LIBKLEO_LOG) << "Adding" << addr << "for" << Formatting::displayName(key.protocol()) << "fpr:" << key.primaryFingerprint(); mEncKeys[key.protocol()][addr].push_back(key); } } if (isUnresolved) { // TODO show warning } Q_EMIT q->keysResolved(true, false); } KeyResolver *const q; QString mSender; QStringList mRecipients; QMap > mSigKeys; QMap > >mEncKeys; QMap > mOverrides; QStringList mUnresolvedPGP, mUnresolvedCMS; Protocol mFormat; QStringList mFatalErrors; bool mEncrypt, mSign; bool mAllowMixed; // The cache is needed as a member variable to avoid rebuilding // it between calls if we are the only user. std::shared_ptr mCache; std::shared_ptr mDialog; Qt::WindowFlags mDialogWindowFlags; Protocol mPreferredProtocol; int mMinimumValidity; QString mCompliance; }; void KeyResolver::start(bool showApproval, QWidget *parentWidget) { qCDebug(LIBKLEO_LOG) << "Starting "; if (!d->mSign && !d->mEncrypt) { // nothing to do return Q_EMIT keysResolved(true, 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 && !showApproval) { if (pgpOnly) { d->mSigKeys.remove(CMS); d->mEncKeys.remove(CMS); - } - if (cmsOnly) { + } else if (cmsOnly) { d->mSigKeys.remove(OpenPGP); d->mEncKeys.remove(OpenPGP); } qCDebug(LIBKLEO_LOG) << "Automatic key resolution done."; Q_EMIT keysResolved(true, false); return; } else if (!needsUser) { qCDebug(LIBKLEO_LOG) << "No need for the user showing approval anyway."; } d->showApprovalDialog(parentWidget); } KeyResolver::KeyResolver(bool encrypt, bool sign, Protocol fmt, bool allowMixed) : d(new Private(this, encrypt, sign, fmt, allowMixed)) { } Kleo::KeyResolver::~KeyResolver() = default; void KeyResolver::setRecipients(const QStringList &addresses) { d->addRecpients(addresses); } void KeyResolver::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; } if (d->mEncrypt) { if (!d->mUnresolvedCMS.contains(normStr)) { d->mUnresolvedCMS << normStr; } if (!d->mUnresolvedPGP.contains(normStr)) { d->mUnresolvedPGP << normStr; } } } void KeyResolver::setOverrideKeys(const QMap > &overrides) { QMap 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); } } QMap > > KeyResolver::encryptionKeys() const { return d->mEncKeys; } QMap > KeyResolver::signingKeys() const { return d->mSigKeys; } QMap > KeyResolver::overrideKeys() const { return d->mOverrides; } void KeyResolver::setDialogWindowFlags(Qt::WindowFlags flags) { d->mDialogWindowFlags = flags; } void KeyResolver::setPreferredProtocol(Protocol proto) { d->mPreferredProtocol = proto; } void KeyResolver::setMinimumValidity(int validity) { d->mMinimumValidity = validity; }