202 lines
4.4 KiB
C++
202 lines
4.4 KiB
C++
/*!
|
|
* \copyright Copyright (c) 2014 Governikus GmbH & Co. KG
|
|
*/
|
|
|
|
#include "pace/PaceHandler.h"
|
|
|
|
#include "asn1/KnownOIDs.h"
|
|
#include "asn1/PACEInfo.h"
|
|
#include "Commands.h"
|
|
#include "FileRef.h"
|
|
#include "pace/ec/EllipticCurveFactory.h"
|
|
#include "pace/KeyAgreement.h"
|
|
#include "PersoSimWorkaround.h"
|
|
|
|
#include <exception>
|
|
#include <QLoggingCategory>
|
|
|
|
using namespace governikus;
|
|
|
|
Q_DECLARE_LOGGING_CATEGORY(card)
|
|
|
|
PaceHandler::PaceHandler(const QSharedPointer<CardConnectionWorker>& pCardConnectionWorker)
|
|
: mCardConnectionWorker(pCardConnectionWorker)
|
|
, mKeyAgreement()
|
|
, mPaceInfo()
|
|
, mIdIcc()
|
|
, mEncryptionKey()
|
|
, mMacKey()
|
|
, mChat()
|
|
, mCarCurr()
|
|
, mCarPrev()
|
|
{
|
|
}
|
|
|
|
|
|
QByteArray PaceHandler::getPaceProtocol() const
|
|
{
|
|
if (!mPaceInfo)
|
|
{
|
|
return QByteArray();
|
|
}
|
|
return mPaceInfo->getProtocol();
|
|
}
|
|
|
|
|
|
CardReturnCode PaceHandler::establishPaceChannel(PACE_PIN_ID pPinId, const QString& pPin)
|
|
{
|
|
auto efCardAccess = mCardConnectionWorker->getReaderInfo().getCardInfo().getEfCardAccess();
|
|
if (!efCardAccess)
|
|
{
|
|
return CardReturnCode::PROTOCOL_ERROR;
|
|
}
|
|
if (!initialize(efCardAccess))
|
|
{
|
|
return CardReturnCode::PROTOCOL_ERROR;
|
|
}
|
|
if (!transmitMSESetAT(pPinId))
|
|
{
|
|
return CardReturnCode::PROTOCOL_ERROR;
|
|
}
|
|
|
|
KeyAgreementStatus keyAgreementStatus = mKeyAgreement->perform(pPin);
|
|
if (keyAgreementStatus == KeyAgreementStatus::PROTOCOLL_ERROR)
|
|
{
|
|
return CardReturnCode::PROTOCOL_ERROR;
|
|
}
|
|
else if (keyAgreementStatus == KeyAgreementStatus::FAILED)
|
|
{
|
|
switch (pPinId)
|
|
{
|
|
case PACE_PIN_ID::PACE_MRZ:
|
|
// No separate error code (yet).
|
|
case PACE_PIN_ID::PACE_CAN:
|
|
return CardReturnCode::INVALID_CAN;
|
|
|
|
case PACE_PIN_ID::PACE_PIN:
|
|
return CardReturnCode::INVALID_PIN;
|
|
|
|
case PACE_PIN_ID::PACE_PUK:
|
|
return CardReturnCode::INVALID_PUK;
|
|
}
|
|
}
|
|
mEncryptionKey = mKeyAgreement->getEncryptionKey();
|
|
mMacKey = mKeyAgreement->getMacKey();
|
|
mCarCurr = mKeyAgreement->getCarCurr();
|
|
mCarPrev = mKeyAgreement->getCarPrev();
|
|
mIdIcc = mKeyAgreement->getCompressedCardPublicKey();
|
|
qCDebug(card) << "Pace channel established";
|
|
return CardReturnCode::OK;
|
|
}
|
|
|
|
|
|
bool PaceHandler::initialize(const QSharedPointer<const EFCardAccess>& pEfCardAccess)
|
|
{
|
|
if (!pEfCardAccess)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const auto& infos = pEfCardAccess->getPACEInfos();
|
|
for (const auto& paceInfo : infos)
|
|
{
|
|
if (isSupportedProtocol(paceInfo))
|
|
{
|
|
mPaceInfo = paceInfo;
|
|
mKeyAgreement = KeyAgreement::create(mPaceInfo, mCardConnectionWorker);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!mKeyAgreement)
|
|
{
|
|
qCCritical(card) << "No supported domain parameters found";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PaceHandler::isSupportedProtocol(const QSharedPointer<const PACEInfo>& pPaceInfo) const
|
|
{
|
|
const auto protocol = pPaceInfo->getProtocol();
|
|
|
|
if (protocol == KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_128 ||
|
|
protocol == KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_192 ||
|
|
protocol == KnownOIDs::id_PACE::ECDH::GM_AES_CBC_CMAC_256)
|
|
{
|
|
if (pPaceInfo->isStandardizedDomainParameters())
|
|
{
|
|
qCDebug(card) << "Use ECDH with standardized domain parameters: " << pPaceInfo->getProtocol();
|
|
return true;
|
|
}
|
|
}
|
|
qCWarning(card) << "Unsupported domain parameters: " << pPaceInfo->getProtocol();
|
|
return false;
|
|
}
|
|
|
|
|
|
bool PaceHandler::transmitMSESetAT(PACE_PIN_ID pPinId)
|
|
{
|
|
PersoSimWorkaround::sendingMseSetAt(mCardConnectionWorker);
|
|
|
|
MSEBuilder mseBuilder(MSEBuilder::P1::PERFORM_SECURITY_OPERATION, MSEBuilder::P2::SET_AT);
|
|
mseBuilder.setOid(mPaceInfo->getProtocolValueBytes());
|
|
mseBuilder.setPublicKey(pPinId);
|
|
mseBuilder.setPrivateKey(mPaceInfo->getParameterId());
|
|
if (!mChat.isNull())
|
|
{
|
|
mseBuilder.setChat(mChat);
|
|
}
|
|
|
|
ResponseApdu response;
|
|
CardReturnCode returnCode = mCardConnectionWorker->transmit(mseBuilder.build(), response);
|
|
if (returnCode != CardReturnCode::OK)
|
|
{
|
|
qCCritical(card) << "Error on MSE:Set AT";
|
|
return false;
|
|
}
|
|
if (response.getReturnCode() != StatusCode::SUCCESS && response.getReturnCode() != StatusCode::PIN_RETRY_COUNT_2 && response.getReturnCode() != StatusCode::PIN_SUSPENDED)
|
|
{
|
|
qCCritical(card) << "Error on MSE:Set AT";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void PaceHandler::setChat(const QByteArray& pChat)
|
|
{
|
|
mChat = pChat;
|
|
}
|
|
|
|
|
|
const QByteArray& PaceHandler::getEncryptionKey() const
|
|
{
|
|
return mEncryptionKey;
|
|
}
|
|
|
|
|
|
const QByteArray& PaceHandler::getMacKey() const
|
|
{
|
|
return mMacKey;
|
|
}
|
|
|
|
|
|
const QByteArray& PaceHandler::getCarCurr() const
|
|
{
|
|
return mCarCurr;
|
|
}
|
|
|
|
|
|
const QByteArray& PaceHandler::getCarPrev() const
|
|
{
|
|
return mCarPrev;
|
|
}
|
|
|
|
|
|
const QByteArray& PaceHandler::getIdIcc() const
|
|
{
|
|
return mIdIcc;
|
|
}
|