AusweisApp2/src/card/base/Reader.cpp

204 lines
4.8 KiB
C++

/*!
* \copyright Copyright (c) 2014 Governikus GmbH & Co. KG
*/
#include "asn1/PACEInfo.h"
#include "CardConnectionWorker.h"
#include "PersoSimWorkaround.h"
#include "Reader.h"
#include <QLoggingCategory>
using namespace governikus;
Q_DECLARE_LOGGING_CATEGORY(card)
Q_DECLARE_LOGGING_CATEGORY(support)
Reader::Reader(ReaderManagerPlugInType pPlugInType, const QString& pReaderName, ReaderType pType)
: QObject()
, mReaderInfo(pPlugInType, pReaderName, pType)
, mTimerId(0)
, mUpdateRetryCounter(true)
{
}
Reader::~Reader()
{
}
void Reader::setPukInoperative()
{
mReaderInfo.mCardInfo.mPukInoperative = true;
}
QSharedPointer<CardConnectionWorker> Reader::createCardConnectionWorker()
{
Card* currentCard = getCard();
if (currentCard == nullptr)
{
qCWarning(card) << "No card available";
return QSharedPointer<CardConnectionWorker>();
}
if (currentCard->isConnected())
{
qCWarning(card) << "Card is already connected";
return QSharedPointer<CardConnectionWorker>();
}
if (currentCard->connect() != CardReturnCode::OK)
{
qCCritical(card) << "Cannot connect to card";
return QSharedPointer<CardConnectionWorker>();
}
return CardConnectionWorker::create(this);
}
void Reader::timerEvent(QTimerEvent* pEvent)
{
if (pEvent->timerId() == mTimerId)
{
update();
}
}
void Reader::update()
{
CardEvent cardEvent = updateCard();
fireUpdateSignal(cardEvent);
updateRetryCounterIfNecessary();
}
void Reader::updateRetryCounterIfNecessary()
{
if (!mUpdateRetryCounter || mReaderInfo.getCardInfo().getCardType() != CardType::EID_CARD)
{
return;
}
auto cardConnection = createCardConnectionWorker();
if (cardConnection)
{
updateRetryCounter(cardConnection);
}
}
CardReturnCode Reader::updateRetryCounter(QSharedPointer<CardConnectionWorker> pCardConnectionWorker)
{
int newRetryCounter = -1;
bool newPinDeactivated = false;
CardReturnCode returnCode = getRetryCounter(pCardConnectionWorker, newRetryCounter, newPinDeactivated);
if (returnCode == CardReturnCode::OK)
{
bool changed = (newRetryCounter != mReaderInfo.getRetryCounter()) || (newPinDeactivated != mReaderInfo.isPinDeactivated());
qCInfo(support) << "retrieved retry counter:" << newRetryCounter << ", was:" << mReaderInfo.getRetryCounter() << ", PIN deactivated:" << newPinDeactivated;
mUpdateRetryCounter = false;
mReaderInfo.mCardInfo.mRetryCounter = newRetryCounter;
mReaderInfo.mCardInfo.mPinDeactivated = newPinDeactivated;
if (changed)
{
qCDebug(card) << "fireCardRetryCounterChanged";
Q_EMIT fireCardRetryCounterChanged(mReaderInfo.getName());
}
}
return returnCode;
}
CardReturnCode Reader::getRetryCounter(QSharedPointer<CardConnectionWorker> pCardConnectionWorker, int& pRetryCounter, bool& pPinDeactivated)
{
if (!mReaderInfo.getCardInfo().getEfCardAccess())
{
qCCritical(card) << "Cannot get EF.CardAccess";
return CardReturnCode::COMMAND_FAILED;
}
// we don't need to establish PACE with this protocol (i.e. we don't need to support it), so we just take the fist one
const auto& paceInfo = mReaderInfo.getCardInfo().getEfCardAccess()->getPACEInfos().at(0);
QByteArray cryptographicMechanismReference = paceInfo->getProtocolValueBytes();
QByteArray referencePrivateKey = paceInfo->getParameterId();
PersoSimWorkaround::sendingMseSetAt(pCardConnectionWorker);
// MSE:Set AT
MSEBuilder mseBuilder(MSEBuilder::P1::PERFORM_SECURITY_OPERATION, MSEBuilder::P2::SET_AT);
mseBuilder.setOid(cryptographicMechanismReference);
mseBuilder.setPublicKey(PACE_PIN_ID::PACE_PIN);
mseBuilder.setPrivateKey(referencePrivateKey);
ResponseApdu mseSetAtResponse;
CardReturnCode returnCode = pCardConnectionWorker->transmit(mseBuilder.build(), mseSetAtResponse);
if (returnCode != CardReturnCode::OK)
{
return returnCode;
}
StatusCode statusCode = mseSetAtResponse.getReturnCode();
qCDebug(card) << "StatusCode: " << statusCode;
if (statusCode == StatusCode::SUCCESS)
{
pRetryCounter = 3;
}
else if (statusCode == StatusCode::PIN_RETRY_COUNT_2)
{
pRetryCounter = 2;
}
else if (statusCode == StatusCode::PIN_SUSPENDED)
{
pRetryCounter = 1;
}
else if (statusCode == StatusCode::PIN_BLOCKED || statusCode == StatusCode::PIN_DEACTIVATED)
{
pRetryCounter = 0;
}
pPinDeactivated = statusCode == StatusCode::PIN_DEACTIVATED;
return CardReturnCode::OK;
}
void Reader::fireUpdateSignal(CardEvent pCardEvent)
{
switch (pCardEvent)
{
case CardEvent::NONE:
break;
case CardEvent::CARD_INSERTED:
qCInfo(support) << "Card inserted of type" << mReaderInfo.getCardType();
Q_EMIT fireCardInserted(mReaderInfo.getName());
break;
case CardEvent::CARD_REMOVED:
qCInfo(support) << "Card removed";
Q_EMIT fireCardRemoved(mReaderInfo.getName());
break;
}
}
void Reader::onRetryCounterPotentiallyChanged()
{
mUpdateRetryCounter = true;
}
ConnectableReader::~ConnectableReader()
{
}