AusweisApp2/src/card/base/pace/PaceHandler.cpp

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;
}