AusweisApp2/src/card/base/asn1/AuthenticatedAuxiliaryData.cpp

245 lines
6.6 KiB
C++

/*!
* AuthenticatedAuxiliaryData.cpp
*
* \copyright Copyright (c) 2015 Governikus GmbH & Co. KG
*/
#include "ASN1TemplateUtil.h"
#include "ASN1Util.h"
#include "AuthenticatedAuxiliaryData.h"
#include "KnownOIDs.h"
#include <QLoggingCategory>
using namespace governikus;
Q_DECLARE_LOGGING_CATEGORY(card)
namespace governikus
{
using CommunityID = ASN1_OCTET_STRING;
DECLARE_ASN1_FUNCTIONS(CommunityID)
using ValidityDate = ASN1_OCTET_STRING;
DECLARE_ASN1_FUNCTIONS(ValidityDate)
using AgeVerificationDate = ASN1_STRING;
DECLARE_ASN1_FUNCTIONS(AgeVerificationDate)
DECLARE_ASN1_OBJECT(ValidityDate)
/*!
* This defines the AuxDataTemplate object as SEQUENCE without the special tag.
*/
ASN1_SEQUENCE(auxdatatemplate_st) = {
ASN1_SIMPLE(auxdatatemplate_st, mAuxId, ASN1_OBJECT),
ASN1_SIMPLE(auxdatatemplate_st, mExtInfo, ASN1_ANY),
}
ASN1_SEQUENCE_END(auxdatatemplate_st)
/*!
* This defines the AuxDataTemplate object with the special tag 0x13.
*/
ASN1_ITEM_TEMPLATE(AuxDataTemplate) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x13, AuxDataTemplate, auxdatatemplate_st)
ASN1_ITEM_TEMPLATE_END(AuxDataTemplate)
/*!
* This defines the AuthenticatedAuxiliaryData object with the special tag 0x07.
*/
ASN1_ITEM_TEMPLATE(AuthenticatedAuxiliaryData) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF | ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x07, AuthenticatedAuxiliaryData, AuxDataTemplate)
ASN1_ITEM_TEMPLATE_END(AuthenticatedAuxiliaryData)
IMPLEMENT_ASN1_FUNCTIONS(AuthenticatedAuxiliaryData)
IMPLEMENT_ASN1_OBJECT(AuthenticatedAuxiliaryData)
/*!
* This defines the CommunityID with special tag 0x13
*/
ASN1_ITEM_TEMPLATE(CommunityID) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x13, CommunityID, ASN1_OCTET_STRING)
ASN1_ITEM_TEMPLATE_END(CommunityID)
IMPLEMENT_ASN1_FUNCTIONS(CommunityID)
/*!
* This defines the ValidityDate with special tag 0x13
*/
ASN1_ITEM_TEMPLATE(ValidityDate) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x13, ValidityDate, ASN1_OCTET_STRING)
ASN1_ITEM_TEMPLATE_END(ValidityDate)
IMPLEMENT_ASN1_FUNCTIONS(ValidityDate)
IMPLEMENT_ASN1_OBJECT(ValidityDate)
/*!
* This defines the AgeVerificationDate with special tag 0x13
*/
ASN1_ITEM_TEMPLATE(AgeVerificationDate) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_IMPTAG | ASN1_TFLG_APPLICATION, 0x13, AgeVerificationDate, ASN1_OCTET_STRING)
ASN1_ITEM_TEMPLATE_END(AgeVerificationDate)
IMPLEMENT_ASN1_FUNCTIONS(AgeVerificationDate)
} // namespace governikus
QSharedPointer<AuthenticatedAuxiliaryData> AuthenticatedAuxiliaryData::fromHex(const QByteArray& pHexValue)
{
return decode(QByteArray::fromHex(pHexValue));
}
QSharedPointer<AuthenticatedAuxiliaryData> AuthenticatedAuxiliaryData::decode(const QByteArray& pBytes)
{
auto auxDate = decodeObject<AuthenticatedAuxiliaryData>(pBytes);
QByteArrayList oids;
for (int i = 0; i < SKM_sk_num(AuxDataTemplate, auxDate.data()); i++)
{
AuxDataTemplate* auxDataTemplate = SKM_sk_value(AuxDataTemplate, auxDate.data(), i);
const auto oid = Asn1ObjectUtil::convertTo(auxDataTemplate->mAuxId);
if (oids.contains(oid))
{
qCritical(card) << "More than one AuxDataTemplate with OID" << oid;
auxDate.clear();
break;
}
oids += oid;
}
oids.removeOne(KnownOIDs::AuxilaryData::id_CommunityID);
oids.removeOne(KnownOIDs::AuxilaryData::id_DateOfBirth);
oids.removeOne(KnownOIDs::AuxilaryData::id_DateOfExpiry);
if (!oids.isEmpty())
{
qCritical() << "Unknown AuxDataTemplate with oid" << oids.first();
auxDate.clear();
}
return auxDate;
}
QByteArray AuthenticatedAuxiliaryData::encode()
{
return encodeObject(this);
}
bool AuthenticatedAuxiliaryData::hasValidityDate() const
{
return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfExpiry) != nullptr;
}
QDate AuthenticatedAuxiliaryData::getValidityDate() const
{
if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfExpiry))
{
QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo);
auto validityDate = decodeObject<ValidityDate>(extBytes);
if (validityDate != nullptr)
{
auto dateString = QString::fromLatin1(reinterpret_cast<char*>(validityDate->data), validityDate->length);
return QDate::fromString(dateString, QStringLiteral("yyyyMMdd"));
}
}
return QDate();
}
bool AuthenticatedAuxiliaryData::hasAgeVerificationDate() const
{
return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfBirth) != nullptr;
}
QDate AuthenticatedAuxiliaryData::getAgeVerificationDate() const
{
if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_DateOfBirth))
{
QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo);
auto ageVerificationDate = decodeObject<AgeVerificationDate>(extBytes);
if (ageVerificationDate != nullptr)
{
auto dateString = QString::fromLatin1(reinterpret_cast<char*>(ageVerificationDate->data), ageVerificationDate->length);
return QDate::fromString(dateString, QStringLiteral("yyyyMMdd"));
}
}
return QDate();
}
QString AuthenticatedAuxiliaryData::getRequiredAge() const
{
QDateTime now = QDateTime::currentDateTime();
QDate nowDateGMT = now.toUTC().date();
QDate ageVerificationDate = getAgeVerificationDate();
if (nowDateGMT.month() > ageVerificationDate.month() || (nowDateGMT.month() == ageVerificationDate.month() && nowDateGMT.day() >= ageVerificationDate.day()))
{
return QString::number(nowDateGMT.year() - ageVerificationDate.year());
}
else
{
return QString::number(nowDateGMT.year() - ageVerificationDate.year() - 1);
}
}
bool AuthenticatedAuxiliaryData::hasCommunityID() const
{
return getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_CommunityID) != nullptr;
}
QByteArray AuthenticatedAuxiliaryData::getCommunityID() const
{
if (auto auxData = getAuxDataTemplateFor(KnownOIDs::AuxilaryData::id_CommunityID))
{
QByteArray extBytes = Asn1TypeUtil::encode(auxData->mExtInfo);
auto communityId = decodeObject<CommunityID>(extBytes);
if (communityId != nullptr)
{
return QByteArray(reinterpret_cast<char*>(communityId->data), communityId->length).toHex();
}
}
return QByteArray();
}
AuxDataTemplate* AuthenticatedAuxiliaryData::getAuxDataTemplateFor(const QByteArray& pOid) const
{
// unfortunately OpenSSL cannot handle const pointers, so we cast it away
AuthenticatedAuxiliaryData* notConstThis = const_cast<AuthenticatedAuxiliaryData*>(this);
for (int i = 0; i < SKM_sk_num(AuxDataTemplate, notConstThis); i++)
{
AuxDataTemplate* auxDataTemplate = SKM_sk_value(AuxDataTemplate, notConstThis, i);
if (Asn1ObjectUtil::convertTo(auxDataTemplate->mAuxId) == pOid)
{
return auxDataTemplate;
}
}
return nullptr;
}