1 /*  smartcard/card.h
2 
3     This file is part of Kleopatra, the KDE keymanager
4     SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
5     SPDX-FileContributor: Intevation GmbH
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include "card.h"
11 
12 #include "readerstatus.h"
13 
14 #include "kleopatra_debug.h"
15 
16 using namespace Kleo;
17 using namespace Kleo::SmartCard;
18 
19 namespace {
formatVersion(int value)20 static QString formatVersion(int value)
21 {
22     if (value < 0) {
23         return QString();
24     }
25 
26     const unsigned int a = ((value >> 24) & 0xff);
27     const unsigned int b = ((value >> 16) & 0xff);
28     const unsigned int c = ((value >>  8) & 0xff);
29     const unsigned int d = ((value      ) & 0xff);
30     if (a) {
31         return QStringLiteral("%1.%2.%3.%4").arg(QString::number(a), QString::number(b), QString::number(c), QString::number(d));
32     } else if (b) {
33         return QStringLiteral("%1.%2.%3").arg(QString::number(b), QString::number(c), QString::number(d));
34     } else if (c) {
35         return QStringLiteral("%1.%2").arg(QString::number(c), QString::number(d));
36     }
37     return QString::number(d);
38 }
39 }
40 
Card()41 Card::Card()
42 {
43 }
44 
~Card()45 Card::~Card()
46 {
47 }
48 
setStatus(Status s)49 void Card::setStatus(Status s)
50 {
51     mStatus = s;
52 }
53 
status() const54 Card::Status Card::status() const
55 {
56     return mStatus;
57 }
58 
setSerialNumber(const std::string & sn)59 void Card::setSerialNumber(const std::string &sn)
60 {
61     mSerialNumber = sn;
62 }
63 
serialNumber() const64 std::string Card::serialNumber() const
65 {
66     return mSerialNumber;
67 }
68 
displaySerialNumber() const69 QString Card::displaySerialNumber() const
70 {
71     return mDisplaySerialNumber;
72 }
73 
setDisplaySerialNumber(const QString & serialNumber)74 void Card::setDisplaySerialNumber(const QString &serialNumber)
75 {
76     mDisplaySerialNumber = serialNumber;
77 }
78 
appName() const79 std::string Card::appName() const
80 {
81     return mAppName;
82 }
83 
setAppName(const std::string & name)84 void Card::setAppName(const std::string &name)
85 {
86     mAppName = name;
87 }
88 
setAppVersion(int version)89 void Card::setAppVersion(int version)
90 {
91     mAppVersion = version;
92 }
93 
appVersion() const94 int Card::appVersion() const
95 {
96     return mAppVersion;
97 }
98 
displayAppVersion() const99 QString Card::displayAppVersion() const
100 {
101     return formatVersion(mAppVersion);
102 }
103 
setManufacturer(const std::string & value)104 void Card::setManufacturer(const std::string &value)
105 {
106     if (!manufacturer().empty()) {
107         qCDebug(KLEOPATRA_LOG) << "Card manufacturer is already set; overwriting existing value";
108         mCardInfo.erase("MANUFACTURER");
109     }
110     mCardInfo.insert({"MANUFACTURER", value});
111 }
112 
manufacturer() const113 std::string Card::manufacturer() const
114 {
115     return cardInfo("MANUFACTURER");
116 }
117 
cardType() const118 std::string Card::cardType() const
119 {
120     return mCardType;
121 }
122 
cardVersion() const123 int Card::cardVersion() const
124 {
125     return mCardVersion;
126 }
127 
displayCardVersion() const128 QString Card::displayCardVersion() const
129 {
130     return formatVersion(mCardVersion);
131 }
132 
cardHolder() const133 QString Card::cardHolder() const
134 {
135     return mCardHolder;
136 }
137 
setSigningKeyRef(const std::string & keyRef)138 void Card::setSigningKeyRef(const std::string &keyRef)
139 {
140     mSigningKeyRef = keyRef;
141 }
142 
signingKeyRef() const143 std::string Card::signingKeyRef() const
144 {
145     return mSigningKeyRef;
146 }
147 
hasSigningKey() const148 bool Card::hasSigningKey() const
149 {
150     return !keyInfo(mSigningKeyRef).grip.empty();
151 }
152 
setEncryptionKeyRef(const std::string & keyRef)153 void Card::setEncryptionKeyRef(const std::string &keyRef)
154 {
155     mEncryptionKeyRef = keyRef;
156 }
157 
encryptionKeyRef() const158 std::string Card::encryptionKeyRef() const
159 {
160     return mEncryptionKeyRef;
161 }
162 
hasEncryptionKey() const163 bool Card::hasEncryptionKey() const
164 {
165     return !keyInfo(mEncryptionKeyRef).grip.empty();
166 }
167 
setAuthenticationKeyRef(const std::string & keyRef)168 void Card::setAuthenticationKeyRef(const std::string &keyRef)
169 {
170     mAuthenticationKeyRef = keyRef;
171 }
172 
authenticationKeyRef() const173 std::string Card::authenticationKeyRef() const
174 {
175     return mAuthenticationKeyRef;
176 }
177 
hasAuthenticationKey() const178 bool Card::hasAuthenticationKey() const
179 {
180     return !keyInfo(mAuthenticationKeyRef).grip.empty();
181 }
182 
pinStates() const183 std::vector<Card::PinState> Card::pinStates() const
184 {
185     return mPinStates;
186 }
187 
setPinStates(const std::vector<PinState> & pinStates)188 void Card::setPinStates(const std::vector<PinState> &pinStates)
189 {
190     mPinStates = pinStates;
191 }
192 
hasNullPin() const193 bool Card::hasNullPin() const
194 {
195     return mHasNullPin;
196 }
197 
setHasNullPin(bool value)198 void Card::setHasNullPin(bool value)
199 {
200     mHasNullPin = value;
201 }
202 
canLearnKeys() const203 bool Card::canLearnKeys() const
204 {
205     return mCanLearn;
206 }
207 
setCanLearnKeys(bool value)208 void Card::setCanLearnKeys(bool value)
209 {
210     mCanLearn = value;
211 }
212 
operator ==(const Card & other) const213 bool Card::operator == (const Card &other) const
214 {
215     return mCanLearn == other.mCanLearn
216         && mHasNullPin == other.mHasNullPin
217         && mStatus == other.mStatus
218         && mSerialNumber == other.mSerialNumber
219         && mAppName == other.mAppName
220         && mAppVersion == other.mAppVersion
221         && mCardType == other.mCardType
222         && mCardVersion == other.mCardVersion
223         && mCardHolder == other.mCardHolder
224         && mSigningKeyRef == other.mSigningKeyRef
225         && mEncryptionKeyRef == other.mEncryptionKeyRef
226         && mAuthenticationKeyRef == other.mAuthenticationKeyRef
227         && mPinStates == other.mPinStates
228         && mErrMsg == other.mErrMsg
229         && mKeyInfos == other.mKeyInfos
230         && mCardInfo == other.mCardInfo;
231 }
232 
operator !=(const Card & other) const233 bool Card::operator != (const Card &other) const
234 {
235     return !operator==(other);
236 }
237 
setErrorMsg(const QString & msg)238 void Card::setErrorMsg(const QString &msg)
239 {
240     mErrMsg = msg;
241 }
242 
errorMsg() const243 QString Card::errorMsg() const
244 {
245     return mErrMsg;
246 }
247 
setInitialKeyInfos(const std::vector<KeyPairInfo> & infos)248 void Card::setInitialKeyInfos(const std::vector<KeyPairInfo> &infos)
249 {
250     mKeyInfos = infos;
251 }
252 
keyInfos() const253 const std::vector<KeyPairInfo> & Card::keyInfos() const
254 {
255     return mKeyInfos;
256 }
257 
keyInfo(const std::string & keyRef) const258 const KeyPairInfo & Card::keyInfo(const std::string &keyRef) const
259 {
260     static const KeyPairInfo nullKey;
261     for (const KeyPairInfo &k : mKeyInfos) {
262         if (k.keyRef == keyRef) {
263             return k;
264         }
265     }
266     return nullKey;
267 }
268 
setCardInfo(const std::vector<std::pair<std::string,std::string>> & infos)269 void Card::setCardInfo(const std::vector<std::pair<std::string, std::string>> &infos)
270 {
271     qCDebug(KLEOPATRA_LOG) << "Card" << serialNumber().c_str() << "info:";
272     for (const auto &pair: infos) {
273         qCDebug(KLEOPATRA_LOG) << pair.first.c_str() << ":" << pair.second.c_str();
274         parseCardInfo(pair.first, pair.second);
275     }
276     processCardInfo();
277 }
278 
279 namespace {
parseHexEncodedVersionTuple(const std::string & s)280 static int parseHexEncodedVersionTuple(const std::string &s) {
281     // s is a hex-encoded, unsigned int-packed version tuple,
282     // i.e. each byte represents one part of the version tuple
283     bool ok;
284     const auto version = QByteArray::fromStdString(s).toUInt(&ok, 16);
285     return ok ? version : -1;
286 }
287 }
288 
parseCardInfo(const std::string & name,const std::string & value)289 void Card::parseCardInfo(const std::string &name, const std::string &value)
290 {
291     if (name == "APPVERSION") {
292         mAppVersion = parseHexEncodedVersionTuple(value);
293     } else if (name == "CARDTYPE") {
294         mCardType = value;
295     } else if (name == "CARDVERSION") {
296         mCardVersion = parseHexEncodedVersionTuple(value);
297     } else if (name == "DISP-NAME") {
298         auto list = QString::fromUtf8(QByteArray::fromStdString(value)).
299                     split(QStringLiteral("<<"), Qt::SkipEmptyParts);
300         std::reverse(list.begin(), list.end());
301         mCardHolder = list.join(QLatin1Char(' '));
302     } else if (name == "KEYPAIRINFO") {
303         const KeyPairInfo info = KeyPairInfo::fromStatusLine(value);
304         if (info.grip.empty()) {
305             qCWarning(KLEOPATRA_LOG) << "Invalid KEYPAIRINFO status line" << QString::fromStdString(value);
306             setStatus(Card::CardError);
307         } else {
308             updateKeyInfo(info);
309         }
310     } else if (name == "KEY-FPR") {
311         // handle OpenPGP key fingerprints
312         const auto values = QString::fromStdString(value).split(QLatin1Char(' '));
313         if (values.size() < 2) {
314             qCWarning(KLEOPATRA_LOG) << "Invalid KEY-FPR status line" << QString::fromStdString(value);
315             setStatus(Card::CardError);
316         }
317         const auto keyNumber = values[0];
318         const std::string keyRef = "OPENPGP." + keyNumber.toStdString();
319         const auto fpr = values[1].toStdString();
320         if (keyNumber == QLatin1Char('1') || keyNumber == QLatin1Char('2') || keyNumber == QLatin1Char('3')) {
321             addCardInfo("KLEO-FPR-" + keyRef, fpr);
322         } else {
323             // Maybe more keyslots in the future?
324             qCDebug(KLEOPATRA_LOG) << "Unhandled keyslot" << keyNumber;
325         }
326     } else if (name == "MANUFACTURER") {
327         // the value of MANUFACTURER is the manufacturer ID as unsigned number
328         // optionally followed by the name of the manufacturer, e.g.
329         // 6 Yubico
330         // 65534 unmanaged S/N range
331         // for PKCS#15 cards the manufacturer ID is always 0, e.g.
332         // 0 www.atos.net/cardos [R&S]
333         const auto startOfManufacturerName = value.find(' ');
334         if (startOfManufacturerName != std::string::npos) {
335             addCardInfo(name, value.substr(startOfManufacturerName + 1));
336         }
337     } else {
338         mCardInfo.insert({name, value});
339     }
340 }
341 
processCardInfo()342 void Card::processCardInfo()
343 {
344 }
345 
addCardInfo(const std::string & name,const std::string & value)346 void Card::addCardInfo(const std::string &name, const std::string &value)
347 {
348     mCardInfo.insert({name, value});
349 }
350 
cardInfo(const std::string & name) const351 std::string Card::cardInfo(const std::string &name) const
352 {
353     const auto range = mCardInfo.equal_range(name);
354     return range.first != range.second ? range.first->second : std::string();
355 }
356 
updateKeyInfo(const KeyPairInfo & keyPairInfo)357 void Card::updateKeyInfo(const KeyPairInfo& keyPairInfo)
358 {
359     for (KeyPairInfo &k : mKeyInfos) {
360         if (k.keyRef == keyPairInfo.keyRef) {
361             k.update(keyPairInfo);
362             return;
363         }
364     }
365     mKeyInfos.push_back(keyPairInfo);
366 }
367 
keyFingerprint(const std::string & keyRef) const368 std::string Card::keyFingerprint(const std::string &keyRef) const
369 {
370     return cardInfo("KLEO-FPR-" + keyRef);
371 }
372