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 }