Skip to content

Commit 8960585

Browse files
authored
Thales cards do not return Card NR anymore (open-eid#1371)
IB-8696 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 42b055a commit 8960585

12 files changed

Lines changed: 132 additions & 182 deletions

client/Diagnostics.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ void Diagnostics::generalInfo(QTextStream &s)
122122
continue;
123123

124124
s << "ATR - " << reader.atr() << "<br />";
125-
reader.beginTransaction();
126125
constexpr auto APDU = &QByteArray::fromHex;
127126
auto printAID = [&](QLatin1String label, const QByteArray &apdu)
128127
{

client/MainWindow.cpp

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,16 @@ MainWindow::MainWindow( QWidget *parent )
8686

8787
// Refresh ID card info in card widget
8888
connect(qApp->signer(), &QSigner::cacheChanged, this, &MainWindow::updateSelector);
89-
connect(&QPCSC::instance(), &QPCSC::statusChanged, this, &MainWindow::updateSelector);
9089
connect(qApp->signer(), &QSigner::signDataChanged, this, [this](const TokenData &token) {
91-
updateSelectorData(token);
90+
updateSelector();
9291
updateMyEID(token);
9392
ui->signContainerPage->cardChanged(token.cert(), token.data(QStringLiteral("blocked")).toBool());
9493
});
9594
connect(qApp->signer(), &QSigner::authDataChanged, this, [this](const TokenData &token) {
96-
updateSelectorData(token);
95+
updateSelector();
9796
updateMyEID(token);
9897
ui->cryptoContainerPage->cardChanged(token.cert(), token.data(QStringLiteral("blocked")).toBool());
9998
});
100-
QPCSC::instance().start();
10199

102100
// Refresh card info on "My EID" page
103101
connect(qApp->signer()->smartcard(), &QSmartCard::dataChanged, this, &MainWindow::updateMyEid);
@@ -124,7 +122,7 @@ MainWindow::MainWindow( QWidget *parent )
124122
connect(ui->accordion, &Accordion::changePinClicked, this, &MainWindow::changePinClicked);
125123
connect(ui->cardInfo, &CardWidget::selected, ui->selector, &QToolButton::toggle);
126124

127-
updateSelectorData(qApp->signer()->tokensign());
125+
updateSelector();
128126
updateMyEID(qApp->signer()->tokensign());
129127
ui->signContainerPage->cardChanged(qApp->signer()->tokensign().cert());
130128
ui->cryptoContainerPage->cardChanged(qApp->signer()->tokenauth().cert());
@@ -846,11 +844,7 @@ bool MainWindow::wrapContainer(bool signing)
846844

847845
void MainWindow::updateSelector()
848846
{
849-
updateSelectorData({});
850-
}
851-
852-
void MainWindow::updateSelectorData(TokenData data)
853-
{
847+
TokenData selected;
854848
enum Filter: uint8_t {
855849
Signing,
856850
Decrypting,
@@ -860,24 +854,24 @@ void MainWindow::updateSelectorData(TokenData data)
860854
{
861855
case SignIntro:
862856
case SignDetails:
863-
if(data.isNull()) data = qApp->signer()->tokensign();
857+
selected = qApp->signer()->tokensign();
864858
filter = Signing;
865859
break;
866860
case CryptoIntro:
867861
case CryptoDetails:
868-
if(data.isNull()) data = qApp->signer()->tokenauth();
862+
selected = qApp->signer()->tokenauth();
869863
filter = Decrypting;
870864
break;
871865
case MyEid:
872866
default:
873-
if(data.isNull()) data = qApp->signer()->smartcard()->tokenData();
867+
selected = qApp->signer()->smartcard()->tokenData();
874868
filter = MyEID;
875869
break;
876870
}
877871
QVector<TokenData> list;
878872
for(const TokenData &token: qApp->signer()->cache())
879873
{
880-
if(token.card() == data.card())
874+
if(token.card() == selected.card())
881875
continue;
882876
if(std::any_of(list.cbegin(), list.cend(), [token](const TokenData &item) { return token.card() == item.card(); }))
883877
continue;
@@ -891,12 +885,12 @@ void MainWindow::updateSelectorData(TokenData data)
891885
continue;
892886
list.append(token);
893887
}
894-
ui->noCardInfo->setVisible(ui->cardInfo->token().isNull());
888+
ui->noCardInfo->setVisible(selected.isNull());
895889
ui->selector->setHidden(list.isEmpty());
896890
ui->selector->setChecked(false);
897891
ui->cardInfo->setVisible(ui->noCardInfo->isHidden());
898892
ui->cardInfo->setCursor(ui->selector->isVisible() ? Qt::PointingHandCursor : Qt::ArrowCursor);
899-
ui->cardInfo->update(data, list.size() > 1);
893+
ui->cardInfo->update(selected, list.size() > 1);
900894
if (!QPCSC::instance().serviceRunning())
901895
ui->noCardInfo->update(NoCardInfo::NoPCSC);
902896
else if(QPCSC::instance().readers().isEmpty())
@@ -910,7 +904,7 @@ void MainWindow::updateSelectorData(TokenData data)
910904
if(show)
911905
{
912906
auto *cardPopup = new CardPopup(list, this);
913-
connect(cardPopup, &CardPopup::activated, qApp->signer(), &QSigner::selectCard, Qt::QueuedConnection);
907+
connect(cardPopup, &CardPopup::activated, qApp->signer(), &QSigner::selectCard);
914908
connect(cardPopup, &CardPopup::activated, this, [this] { ui->selector->setChecked(false); });
915909
cardPopup->show();
916910
}

client/MainWindow.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class MainWindow final : public QWidget
8383
void sign(F &&sign);
8484
bool validateFiles(const QString &container, const QStringList &files);
8585
void updateSelector();
86-
void updateSelectorData(TokenData data);
8786
void updateMyEID(const TokenData &t);
8887
void updateMyEid(const QSmartCardData &data);
8988
bool wrap(const QString& wrappedFile, bool enclose);

client/QCNG.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
#include "SslCertificate.h"
2424
#include "TokenData.h"
2525

26+
#include <QtCore/QUuid>
2627
#include <QtCore/QLoggingCategory>
28+
#include <QtCore/QRegularExpression>
2729
#include <QtNetwork/QSslKey>
2830

2931
using namespace Qt::Literals::StringLiterals;
@@ -220,7 +222,9 @@ QList<TokenData> QCNG::tokens() const
220222
if(QByteArray tmp = prop(key, NCRYPT_READER_PROPERTY); !tmp.isEmpty())
221223
reader = QString::fromUtf16((const char16_t*)tmp.data());
222224
}
223-
QString guid = prop(h, NCRYPT_SMARTCARD_GUID_PROPERTY).trimmed();
225+
QByteArray guidData = prop(h, NCRYPT_SMARTCARD_GUID_PROPERTY);
226+
static const QRegularExpression reg(QStringLiteral("\\w{1,2}\\d{7} *"));
227+
QString guid = reg.match(guidData).hasMatch() ? guidData.trimmed() : QUuid(*((GUID*)guidData.data())).toString(QUuid::WithBraces);
224228
TokenData &t = result.emplaceBack();
225229
t.setReader(reader);
226230
t.setCard(cert.type() & SslCertificate::EstEidType || cert.type() & SslCertificate::DigiIDType ?
@@ -232,7 +236,8 @@ QList<TokenData> QCNG::tokens() const
232236
qCWarning(CNG) << "key" << t.data(u"provider"_s)
233237
<< "spec" << t.data(u"spec"_s)
234238
<< "alg" << QStringView(keyname->pszAlgid)
235-
<< "flags" << keyname->dwFlags;
239+
<< "flags" << keyname->dwFlags
240+
<< t.card();
236241
if(cert.publicKey().algorithm() != QSsl::Rsa || reader.isEmpty())
237242
continue;
238243

client/QPCSC.cpp

Lines changed: 33 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ QHash<DRIVER_FEATURES,quint32> QPCSCReader::Private::features()
7676
for(const auto &f: feature)
7777
{
7878
if(f.tag)
79-
featuresList[DRIVER_FEATURES(f.tag)] = qFromBigEndian<quint32>(f.value);
79+
featuresList[f.tag] = qFromBigEndian<quint32>(f.value);
8080
}
8181
return featuresList;
8282
}
@@ -94,10 +94,12 @@ QPCSC::QPCSC()
9494
QPCSC::~QPCSC()
9595
{
9696
requestInterruption();
97+
d->sleepCond.wakeAll();
98+
if(d->thread)
99+
SC(Cancel, d->thread);
97100
wait();
98-
if( d->context )
101+
if(d->context)
99102
SC(ReleaseContext, d->context);
100-
qDeleteAll(d->lock);
101103
delete d;
102104
}
103105

@@ -138,23 +140,30 @@ void QPCSC::run()
138140
std::vector<SCARD_READERSTATE> list;
139141
while(!isInterruptionRequested())
140142
{
141-
if(!pcsc.serviceRunning())
142-
{
143-
sleep(5);
144-
continue;
145-
}
146143
// "\\?PnP?\Notification" does not work on macOS
147144
QByteArray data = pcsc.rawReaders();
148145
if(data.isEmpty())
149146
{
150-
sleep(5);
147+
QMutexLocker locker(&d->sleepMutex);
148+
if (isInterruptionRequested())
149+
break;
150+
d->sleepCond.wait(&d->sleepMutex, 5000);
151151
continue;
152152
}
153153
for(const char *name = data.constData(); *name; name += strlen(name) + 1)
154154
{
155155
if(std::none_of(list.cbegin(), list.cend(), [&name](const SCARD_READERSTATE &state) { return strcmp(state.szReader, name) == 0; }))
156156
list.push_back({ strdup(name), nullptr, 0, 0, 0, {} });
157157
}
158+
if(list.empty())
159+
{
160+
QMutexLocker locker(&d->sleepMutex);
161+
if (isInterruptionRequested())
162+
break;
163+
d->sleepCond.wait(&d->sleepMutex, 5000);
164+
continue;
165+
}
166+
d->thread = pcsc.d->context;
158167
if(SC(GetStatusChange, pcsc.d->context, 5*1000U, list.data(), DWORD(list.size())) != SCARD_S_SUCCESS)
159168
continue;
160169
for(auto i = list.begin(); i != list.end(); )
@@ -164,6 +173,8 @@ void QPCSC::run()
164173
++i;
165174
continue;
166175
}
176+
if((i->dwCurrentState & SCARD_STATE_PRESENT) != (i->dwEventState & SCARD_STATE_PRESENT))
177+
Q_EMIT cardChanged();
167178
i->dwCurrentState = i->dwEventState;
168179
qCDebug(SCard) << "New state: " << QString::fromLocal8Bit(i->szReader) << stateToString(i->dwCurrentState);
169180
Q_EMIT statusChanged(QString::fromLocal8Bit(i->szReader), stateToString(i->dwCurrentState));
@@ -176,6 +187,7 @@ void QPCSC::run()
176187
++i;
177188
}
178189
}
190+
d->thread = {};
179191
}
180192

181193
bool QPCSC::serviceRunning() const
@@ -191,19 +203,19 @@ bool QPCSC::serviceRunning() const
191203
QPCSCReader::QPCSCReader( const QString &reader, QPCSC *parent )
192204
: d(new Private)
193205
{
194-
if(!parent->d->lock.contains(reader))
195-
parent->d->lock[reader] = new QMutex();
196-
parent->d->lock[reader]->lock();
197206
d->d = parent->d;
198207
d->reader = reader.toUtf8();
199208
d->state.szReader = d->reader.constData();
200-
updateState();
209+
if(parent->d->context)
210+
SC(GetStatusChange, d->d->context, 0, &d->state, 1U);
201211
}
202212

203213
QPCSCReader::~QPCSCReader()
204214
{
205-
disconnect();
206-
d->d->lock[d->reader]->unlock();
215+
if(d->isTransacted)
216+
SC(EndTransaction, d->card, SCARD_LEAVE_CARD);
217+
if(d->card)
218+
SC(Disconnect, d->card, SCARD_LEAVE_CARD);
207219
delete d;
208220
}
209221

@@ -212,29 +224,12 @@ QByteArray QPCSCReader::atr() const
212224
return QByteArray::fromRawData((const char*)d->state.rgbAtr, int(d->state.cbAtr)).toHex().toUpper();
213225
}
214226

215-
bool QPCSCReader::beginTransaction()
216-
{
217-
return d->isTransacted = SC(BeginTransaction, d->card) == SCARD_S_SUCCESS;
218-
}
219-
220227
bool QPCSCReader::connect(Connect connect, Mode mode)
221228
{
222-
LONG err = SC(Connect, d->d->context, d->state.szReader, connect, mode, &d->card, &d->io.dwProtocol);
223-
updateState();
224-
return err == SCARD_S_SUCCESS;
225-
}
226-
227-
void QPCSCReader::disconnect( Reset reset )
228-
{
229-
if(d->isTransacted)
230-
SC(EndTransaction, d->card, reset);
231-
d->isTransacted = false;
232-
if( d->card )
233-
SC(Disconnect, d->card, reset);
234-
d->io.dwProtocol = SCARD_PROTOCOL_UNDEFINED;
235-
d->card = {};
236-
d->featuresList.clear();
237-
updateState();
229+
if(SC(Connect, d->d->context, d->state.szReader, connect, mode, &d->card, &d->io.dwProtocol) != SCARD_S_SUCCESS)
230+
return false;
231+
d->isTransacted = SC(BeginTransaction, d->card) == SCARD_S_SUCCESS;
232+
return true;
238233
}
239234

240235
bool QPCSCReader::isPinPad() const
@@ -272,7 +267,7 @@ QHash<QPCSCReader::Properties, int> QPCSCReader::properties() const
272267
int tag = *p++, len = *p++, value = 0;
273268
for(int i = 0; i < len; ++i)
274269
value |= *p++ << 8 * i;
275-
properties[Properties(tag)] = value;
270+
properties.emplace(Properties(tag), value);
276271
}
277272
}
278273
return properties;
@@ -303,7 +298,7 @@ QPCSCReader::Result QPCSCReader::transfer( const QByteArray &apdu ) const
303298
case 0x6100: // Read more
304299
{
305300
QByteArray cmd( "\x00\xC0\x00\x00\x00", 5 );
306-
cmd[4] = data.at(int(size - 1));
301+
cmd[4] = char(result.SW);
307302
Result result2 = transfer( cmd );
308303
result2.data.prepend(result.data);
309304
return result2;
@@ -397,16 +392,3 @@ QPCSCReader::Result QPCSCReader::transferCTL(const QByteArray &apdu, bool verify
397392
if(!result.data.isEmpty()) qCDebug(APDU).nospace().noquote() << result.data.toHex();
398393
return result;
399394
}
400-
401-
bool QPCSCReader::updateState( quint32 msec )
402-
{
403-
if(!d->d->context)
404-
return false;
405-
d->state.dwCurrentState = d->state.dwEventState;
406-
switch(SC(GetStatusChange, d->d->context, msec, &d->state, 1U))
407-
{
408-
case LONG(SCARD_S_SUCCESS): return true;
409-
case LONG(SCARD_E_TIMEOUT): return msec == 0;
410-
default: return false;
411-
}
412-
}

client/QPCSC.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class QPCSC final: public QThread
3636

3737
Q_SIGNALS:
3838
void statusChanged(const QString &reader, const QStringList &state);
39+
void cardChanged();
3940

4041
private:
4142
QPCSC();
@@ -44,7 +45,7 @@ class QPCSC final: public QThread
4445
QByteArray rawReaders() const;
4546
void run() final;
4647

47-
class Private;
48+
struct Private;
4849
Private *d;
4950

5051
friend class QPCSCReader;
@@ -61,7 +62,7 @@ class QPCSCReader final: public QObject
6162
constexpr operator bool() const { return SW == 0x9000; }
6263
};
6364

64-
enum Properties {
65+
enum Properties : quint8 {
6566
wLcdLayout = 0x01,
6667
bEntryValidationCondition = 0x02,
6768
bTimeOut2 = 0x03,
@@ -76,21 +77,20 @@ class QPCSCReader final: public QObject
7677
wIdProduct = 0x0C
7778
};
7879

79-
enum Connect {
80+
enum Connect : quint8 {
8081
Exclusive = 1,
8182
Shared = 2,
8283
Direct = 3
8384
};
8485

85-
enum Reset
86-
{
86+
enum Reset : quint8 {
8787
LeaveCard = 0,
8888
ResetCard = 1,
8989
UnpowerCard = 2,
9090
EjectCard = 3
9191
};
9292

93-
enum Mode {
93+
enum Mode : quint8 {
9494
Undefined = 0,
9595
T0 = 1,
9696
T1 = 2
@@ -105,17 +105,14 @@ class QPCSCReader final: public QObject
105105
QString name() const;
106106
QHash<Properties,int> properties() const;
107107
QStringList state() const;
108-
bool updateState( quint32 msec = 0 );
109108

110109
bool connect( Connect connect = Shared, Mode mode = Mode(T0|T1) );
111-
void disconnect( Reset reset = LeaveCard );
112-
bool beginTransaction();
113110
Result transfer( const QByteArray &apdu ) const;
114111
Result transferCTL(const QByteArray &apdu, bool verify, quint16 lang = 0,
115112
quint8 minlen = 4, quint8 newPINOffset = 0, bool requestCurrentPIN = true) const;
116113

117114
private:
118115
Q_DISABLE_COPY(QPCSCReader)
119-
class Private;
116+
struct Private;
120117
Private *d;
121118
};

0 commit comments

Comments
 (0)