aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/model/GpgOpenPGPCard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/model/GpgOpenPGPCard.cpp')
-rw-r--r--src/core/model/GpgOpenPGPCard.cpp172
1 files changed, 142 insertions, 30 deletions
diff --git a/src/core/model/GpgOpenPGPCard.cpp b/src/core/model/GpgOpenPGPCard.cpp
index f0d8c9cd..ddc9a40e 100644
--- a/src/core/model/GpgOpenPGPCard.cpp
+++ b/src/core/model/GpgOpenPGPCard.cpp
@@ -28,7 +28,6 @@
#include "GpgOpenPGPCard.h"
-#include "core/model/GpgCardKeyPairInfo.h"
#include "core/utils/CommonUtils.h"
namespace GpgFrontend {
@@ -46,39 +45,33 @@ void GpgFrontend::GpgOpenPGPCard::parse_card_info(const QString& name,
std::reverse(list.begin(), list.end());
card_holder =
list.join(QLatin1Char(' ')).replace(QLatin1Char('<'), QLatin1Char(' '));
- } else if (name == "KEYPAIRINFO") {
- const GpgCardKeyPairInfo info = GpgCardKeyPairInfo(value);
- if (info.grip.isEmpty()) {
- LOG_W() << "invalid KEYPAIRINFO status line" << value;
- good = false;
- }
- } else if (name == "KEY-FPR") {
- const auto values = value.split(QLatin1Char(' '));
- if (values.size() < 2) {
- LOG_W() << "invalid KEY-FPR status line" << value;
- good = false;
- return;
- }
-
- const auto& key_number = values[0].toInt();
- const auto& fpr = values[1];
- fprs.insert(key_number, fpr);
-
+ } else if (name == "KEYPAIRINFO" || name == "KEY-FPR" || name == "KEY-TIME") {
+ parse_card_key_info(name, value);
} else if (name == "MANUFACTURER") {
- // the value of MANUFACTURER is the manufacturer ID as unsigned number
- // optionally followed by the name of the manufacturer, e.g.
- // 6 Yubico
- // 65534 unmanaged S/N range
- // for PKCS#15 cards the manufacturer ID is always 0, e.g.
- // 0 www.atos.net/cardos [R&S]
- auto space_index = value.indexOf(' ');
- if (space_index != -1) {
- card_infos.insert(name, value.mid(space_index + 1).trimmed());
- }
+ const auto values = value.split(QLatin1Char(' '));
+ if (values.size() < 2) return;
+ manufacturer_id = values.front().toInt();
+ manufacturer = values.back();
+ } else if (name == "DISP-SEX") {
+ display_sex = value == "1" ? "Male" : value == "2" ? "Female" : "Unknown";
+ } else if (name == "CHV-STATUS") {
+ parse_chv_status(value);
+ } else if (name == "EXTCAP") {
+ parse_ext_capability(value);
+ } else if (name == "KDF") {
+ parse_kdf_status(value);
+ } else if (name.startsWith("UIF-")) {
+ parse_uif(name, value);
} else {
- card_infos.insert(name, value);
+ additional_card_infos.insert(name, value);
}
+
+ reader = additional_card_infos.value("READER").replace('+', ' ');
+ serial_number = additional_card_infos.value("SERIALNO");
+ app_type = additional_card_infos.value("APPTYPE");
+ display_language = additional_card_infos.value("DISP-LANG");
}
+
GpgOpenPGPCard::GpgOpenPGPCard(const QStringList& status) : good(true) {
for (const QString& line : status) {
auto tokens = line.split(' ', Qt::SkipEmptyParts);
@@ -88,4 +81,123 @@ GpgOpenPGPCard::GpgOpenPGPCard(const QStringList& status) : good(true) {
parse_card_info(name, value);
}
}
+
+void GpgOpenPGPCard::parse_chv_status(const QString& value) {
+ auto tokens = value.trimmed().split('+', Qt::SkipEmptyParts);
+
+ int index = 0;
+
+ if (index < tokens.size()) chv1_cached = tokens[index++].toInt();
+
+ // chv_max_len[3]
+ for (int i = 0; i < 3 && index < tokens.size(); ++i) {
+ chv_max_len[i] = tokens[index++].toInt();
+ }
+
+ // chv_retry[3]
+ for (int i = 0; i < 3 && index < tokens.size(); ++i) {
+ chv_retry[i] = tokens[index++].toInt();
+ }
+}
+
+void GpgOpenPGPCard::parse_ext_capability(const QString& value) {
+ auto parts = value.trimmed().split("+");
+
+ for (const QString& part : parts) {
+ auto equal_pos = part.indexOf('=');
+ if (equal_pos == -1) continue;
+
+ auto key = part.left(equal_pos).trimmed();
+ auto value = part.mid(equal_pos + 1).trimmed();
+
+ bool ok = false;
+ int ivalue = value.toInt(&ok);
+
+ if (key == "ki") {
+ ext_cap.ki = (ivalue == 1);
+ } else if (key == "aac") {
+ ext_cap.aac = (ivalue == 1);
+ } else if (key == "bt") {
+ ext_cap.bt = (ivalue == 1);
+ } else if (key == "kdf") {
+ ext_cap.kdf = (ivalue == 1);
+ } else if (key == "si" && ok) {
+ ext_cap.status_indicator = ivalue;
+ }
+ }
+}
+
+void GpgOpenPGPCard::parse_kdf_status(const QString& value) {
+ auto decoded = QByteArray::fromPercentEncoding(value.toUtf8());
+
+ if (decoded.size() < 23) {
+ kdf_do_enabled = 0;
+ return;
+ }
+
+ if (static_cast<quint8>(decoded[2]) != 0x03) {
+ kdf_do_enabled = 0;
+ } else if (static_cast<quint8>(decoded[22]) != 0x85) {
+ kdf_do_enabled = 1;
+ } else {
+ kdf_do_enabled = 2;
+ }
+}
+
+void GpgOpenPGPCard::parse_uif(const QString& name, const QString& value) {
+ auto index = name.back().digitValue() - 1;
+ if (index < 0 || index > 2) return;
+
+ auto decoded = QByteArray::fromPercentEncoding(value.toUtf8());
+ bool enabled = !decoded.isEmpty() && static_cast<quint8>(decoded[0]) != 0xFF;
+
+ switch (index) {
+ case 0:
+ uif.sign = enabled;
+ break;
+ case 1:
+ uif.encrypt = enabled;
+ break;
+ case 2:
+ uif.auth = enabled;
+ break;
+ }
+}
+
+void GpgOpenPGPCard::parse_card_key_info(const QString& name,
+ const QString& value) {
+ if (name == "KEY-FPR") {
+ auto tokens = value.split(' ');
+ if (tokens.size() >= 2) {
+ int no = tokens[0].toInt();
+ card_keys_info[no].fingerprint = tokens[1].toUpper();
+ }
+ } else if (name == "KEY-TIME") {
+ auto tokens = value.split(' ');
+ if (tokens.size() >= 2) {
+ int no = tokens.front().toInt();
+ qint64 ts = tokens.back().toLongLong();
+ card_keys_info[no].created =
+ QDateTime::fromSecsSinceEpoch(ts, QTimeZone::UTC);
+ }
+ } else if (name == "KEYPAIRINFO") {
+ auto tokens = value.split(' ');
+ if (tokens.size() < 2) return;
+
+ auto key_type_tokens = tokens[1].split('.');
+ if (key_type_tokens.size() < 2) return;
+
+ int no = key_type_tokens[1].toInt();
+ card_keys_info[no].key_type = key_type_tokens[0];
+ card_keys_info[no].grip = tokens[0].toUpper();
+
+ if (tokens.size() >= 3) {
+ card_keys_info[no].usage = tokens[2].toUpper();
+ }
+
+ if (tokens.size() >= 5) {
+ card_keys_info[no].algo = tokens[4].toUpper();
+ }
+ }
+}
} // namespace GpgFrontend