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