File indexing completed on 2024-06-23 05:14:11
0001 /* smartcard/netkeycard.cpp 0002 0003 This file is part of Kleopatra, the KDE keymanager 0004 SPDX-FileCopyrightText: 2017 Intevation GmbH 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "netkeycard.h" 0010 0011 #include "keypairinfo.h" 0012 0013 #include "kleopatra_debug.h" 0014 0015 #include <Libkleo/Algorithm> 0016 #include <Libkleo/Formatting> 0017 #include <Libkleo/Predicates> 0018 0019 #include <gpgme++/context.h> 0020 #include <gpgme++/error.h> 0021 #include <gpgme++/keylistresult.h> 0022 0023 #include <memory> 0024 #include <string> 0025 0026 using namespace Kleo; 0027 using namespace Kleo::SmartCard; 0028 0029 // static 0030 const std::string NetKeyCard::AppName = "nks"; 0031 0032 namespace 0033 { 0034 static GpgME::Key lookup_key(GpgME::Context *ctx, const std::string &keyGrip) 0035 { 0036 if (!ctx || keyGrip.empty()) { 0037 return GpgME::Key(); 0038 } 0039 const std::string pattern = '&' + keyGrip; 0040 qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: pattern=" << pattern.c_str(); 0041 if (const auto err = ctx->startKeyListing(pattern.c_str())) { 0042 qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: startKeyListing failed:" << Formatting::errorAsString(err); 0043 return GpgME::Key(); 0044 } 0045 GpgME::Error e; 0046 const auto key = ctx->nextKey(e); 0047 ctx->endKeyListing(); 0048 qCDebug(KLEOPATRA_LOG) << "parse_keypairinfo_and_lookup_key: e=" << e.code() << "; key.isNull()" << key.isNull(); 0049 return key; 0050 } 0051 0052 } // namespace 0053 0054 NetKeyCard::NetKeyCard(const Card &card) 0055 : Card(card) 0056 { 0057 setAppName(AppName); 0058 } 0059 0060 // static 0061 std::string NetKeyCard::nksPinKeyRef() 0062 { 0063 return std::string("PW1.CH"); 0064 } 0065 0066 // static 0067 std::string NetKeyCard::sigGPinKeyRef() 0068 { 0069 return std::string("PW1.CH.SIG"); 0070 } 0071 0072 void NetKeyCard::processCardInfo() 0073 { 0074 setKeyPairInfo(keyInfos()); 0075 } 0076 0077 void NetKeyCard::setKeyPairInfo(const std::vector<KeyPairInfo> &infos) 0078 { 0079 // check that any of the keys are new 0080 const std::unique_ptr<GpgME::Context> klc(GpgME::Context::createForProtocol(GpgME::CMS)); 0081 if (!klc.get()) { 0082 return; 0083 } 0084 klc->setKeyListMode(GpgME::Ephemeral); 0085 klc->addKeyListMode(GpgME::Validate); 0086 0087 setCanLearnKeys(false); 0088 mKeys.clear(); 0089 for (const auto &info : infos) { 0090 const auto key = lookup_key(klc.get(), info.grip); 0091 if (key.isNull()) { 0092 setCanLearnKeys(true); 0093 } else { 0094 mKeys.push_back(key); 0095 } 0096 } 0097 } 0098 0099 // State 0 -> NKS PIN Retry counter 0100 // State 1 -> NKS PUK Retry counter 0101 // State 2 -> SigG PIN Retry counter 0102 // State 3 -> SigG PUK Retry counter 0103 0104 bool NetKeyCard::hasNKSNullPin() const 0105 { 0106 const auto states = pinStates(); 0107 if (states.size() < 2) { 0108 qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << states.size(); 0109 return false; 0110 } 0111 return states[0] == Card::NullPin; 0112 } 0113 0114 bool NetKeyCard::hasSigGNullPin() const 0115 { 0116 const auto states = pinStates(); 0117 if (states.size() < 4) { 0118 qCWarning(KLEOPATRA_LOG) << "Invalid size of pin states:" << states.size(); 0119 return false; 0120 } 0121 return states[2] == Card::NullPin; 0122 } 0123 0124 std::vector<GpgME::Key> NetKeyCard::keys() const 0125 { 0126 return mKeys; 0127 } 0128 0129 bool NetKeyCard::operator==(const Card &other) const 0130 { 0131 static const _detail::ByFingerprint<std::equal_to> keysHaveSameFingerprint; 0132 0133 if (!Card::operator==(other)) { 0134 qCDebug(KLEOPATRA_LOG) << "NetKeyCard" << __func__ << "Card don't match"; 0135 return false; 0136 } 0137 0138 const auto otherNetKeyCard = dynamic_cast<const NetKeyCard *>(&other); 0139 if (!otherNetKeyCard) { 0140 qCWarning(KLEOPATRA_LOG) << "Failed to cast other card to NetKeyCard"; 0141 return false; 0142 } 0143 if (mKeys.size() != otherNetKeyCard->mKeys.size()) { 0144 qCDebug(KLEOPATRA_LOG) << "NetKeyCard" << __func__ << "Number of keys doesn't match"; 0145 return false; 0146 } 0147 const auto otherHasKey = [otherNetKeyCard](const GpgME::Key &key) { 0148 return Kleo::any_of(otherNetKeyCard->mKeys, [key](const GpgME::Key &otherKey) { 0149 return keysHaveSameFingerprint(key, otherKey); 0150 }); 0151 }; 0152 const bool result = Kleo::all_of(mKeys, otherHasKey); 0153 qCDebug(KLEOPATRA_LOG) << "NetKeyCard" << __func__ << "Keys match?" << result; 0154 return result; 0155 }