AusweisApp2/src/core/states/StatePreVerification.cpp

153 lines
4.2 KiB
C++

/*!
* \copyright Copyright (c) 2014-2018 Governikus GmbH & Co. KG, Germany
*/
#include "StatePreVerification.h"
#include "asn1/CVCertificateChainBuilder.h"
#include "asn1/SignatureChecker.h"
#include "AppSettings.h"
#include "EnumHelper.h"
#include "Env.h"
#include "SecureStorage.h"
#include <QVector>
using namespace governikus;
StatePreVerification::StatePreVerification(const QSharedPointer<WorkflowContext>& pContext)
: AbstractGenericState(pContext)
, mTrustedCvcas(CVCertificate::fromHex(SecureStorage::getInstance().getCVRootCertificates(true))
+ CVCertificate::fromHex(SecureStorage::getInstance().getCVRootCertificates(false)))
, mValidationDateTime(QDateTime::currentDateTime())
{
}
void StatePreVerification::run()
{
Q_ASSERT(getContext()->getDidAuthenticateEac1());
qDebug() << "Try to build a cvc chain for one of the known trust points";
CVCertificateChain certificateChain;
for (const auto& trustPoint : mTrustedCvcas)
{
if (!trustPoint->isIssuedBy(*trustPoint))
{
// want a chain with self signed root, because the SignatureChecker needs it
continue;
}
certificateChain = getContext()->getChainStartingWith(trustPoint);
if (certificateChain.isValid())
{
break;
}
}
if (Env::getSingleton<AppSettings>()->getGeneralSettings().isDeveloperMode())
{
if (certificateChain.isProductive())
{
qCritical() << "Using the developer mode is only allowed in a test environment";
updateStatus(GlobalStatus::Code::Workflow_Preverification_Developermode_Error);
Q_EMIT fireAbort();
return;
}
}
if (!AppSettings::getInstance().getPreVerificationSettings().isEnabled())
{
qInfo() << "Pre-verification is disabled";
Q_EMIT fireContinue();
return;
}
if (!certificateChain.isValid())
{
qCritical() << "Pre-verification failed: cannot build certificate chain";
updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
Q_EMIT fireAbort();
return;
}
else if (!SignatureChecker(certificateChain).check())
{
qCritical() << "Pre-verification failed: signature check failed";
updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
Q_EMIT fireAbort();
return;
}
else if (!isValid(certificateChain))
{
qCritical() << "Pre-verification failed: certificate not valid ";
updateStatus(GlobalStatus::Code::Workflow_Preverification_Error);
Q_EMIT fireAbort();
return;
}
saveCvcaLinkCertificates(certificateChain);
Q_EMIT fireContinue();
}
bool StatePreVerification::isValid(const QVector<QSharedPointer<const CVCertificate> >& pCertificates)
{
qDebug() << "Check certificate chain validity on" << mValidationDateTime.toString(Qt::ISODate);
QVectorIterator<QSharedPointer<const CVCertificate> > i(pCertificates);
i.toBack();
while (i.hasPrevious())
{
auto cert = i.previous();
const QDate& expirationDate = cert->getBody().getCertificateExpirationDate();
const QDate& effectiveDate = cert->getBody().getCertificateEffectiveDate();
const QByteArray certInfo = cert->getBody().getCertificateHolderReference();
qDebug() << "CVC" << certInfo
<< cert->getBody().getCHAT().getAccessRole()
<< "| valid from/to"
<< '[' << effectiveDate.toString(Qt::ISODate) << ',' << expirationDate.toString(Qt::ISODate) << ']';
if (!cert->isValidOn(mValidationDateTime))
{
return false;
}
if (cert->getBody().getCHAT().getAccessRole() == AccessRole::CVCA)
{
// only validate up to first CVCA
break;
}
}
return true;
}
void StatePreVerification::saveCvcaLinkCertificates(const QVector<QSharedPointer<const CVCertificate> >& pCertificates)
{
const auto& contains = [](const QVector<QSharedPointer<const CVCertificate> >& pStore, const CVCertificate& pCert) -> bool
{
for (const auto& pCertInStore : pStore)
{
if (*pCertInStore == pCert)
{
return true;
}
}
return false;
};
auto& settings = Env::getSingleton<AppSettings>()->getPreVerificationSettings();
for (const auto& certificate : pCertificates)
{
if (certificate->getBody().getCHAT().getAccessRole() == AccessRole::CVCA && !contains(mTrustedCvcas, *certificate))
{
qInfo() << "Save link certificate" << *certificate;
settings.addLinkCertificate(certificate->encode().toHex());
}
}
settings.save();
}