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

91 lines
2.7 KiB
C++

/*!
* \copyright Copyright (c) 2014 Governikus GmbH & Co. KG
*/
#include "asn1/SignatureChecker.h"
#include "pace/ec/EcUtil.h"
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <QLoggingCategory>
using namespace governikus;
Q_DECLARE_LOGGING_CATEGORY(card)
SignatureChecker::SignatureChecker(const QVector<QSharedPointer<CVCertificate> >& pCertificateChain)
: mCertificateChain(pCertificateChain)
{
}
bool SignatureChecker::check()
{
if (mCertificateChain.isEmpty())
{
qCCritical(card) << "Certificate chain is empty";
return false;
}
auto signingCert = mCertificateChain.at(0);
QSharedPointer<const EC_KEY> key = signingCert->getBody().getPublicKey().getEcKey();
if (!key)
{
qCCritical(card) << "No elliptic curve parameters";
return false;
}
for (const auto& cert : mCertificateChain)
{
if (!checkSignature(cert, signingCert, key.data()))
{
qCCritical(card) << "Certificate verification failed:" << cert->getBody().getCertificateHolderReference();
return false;
}
if (cert->getBody().getPublicKey().getEcKey())
{
key = cert->getBody().getPublicKey().getEcKey();
}
signingCert = cert;
}
return true;
}
bool SignatureChecker::checkSignature(const QSharedPointer<const CVCertificate>& pCert, const QSharedPointer<const CVCertificate>& pSigningCert, const EC_KEY* pKey)
{
// We duplicate the key because we modify it by setting the public point.
QSharedPointer<EC_KEY> signingKey = EcUtil::create(EC_KEY_dup(pKey));
QByteArray uncompPublicPoint = pSigningCert->getBody().getPublicKey().getUncompressedPublicPoint();
const unsigned char* uncompPublicPointData = reinterpret_cast<const unsigned char*>(uncompPublicPoint.constData());
size_t uncompPublicPointLen = static_cast<size_t>(uncompPublicPoint.size());
EC_POINT* publicPoint = EC_POINT_new(EC_KEY_get0_group(signingKey.data()));
const EC_GROUP* ecGroup = EC_KEY_get0_group(signingKey.data());
if (!EC_POINT_oct2point(ecGroup, publicPoint, uncompPublicPointData, uncompPublicPointLen, (BN_CTX*) nullptr))
{
qCCritical(card) << "Cannot decode uncompressed public point";
return false;
}
EC_KEY_set_public_key(signingKey.data(), publicPoint);
QByteArray bodyHash = QCryptographicHash::hash(pCert->getRawBody(), pSigningCert->getBody().getHashAlgorithm());
const unsigned char* dgst = reinterpret_cast<const unsigned char*>(bodyHash.constData());
int dgstlen = bodyHash.size();
int result = ECDSA_do_verify(dgst, dgstlen, pCert->getEcdsaSignature().data(), signingKey.data());
if (result == -1)
{
ERR_load_crypto_strings();
qCCritical(card) << "Signature verification failed, an error occured: " << ERR_error_string(ERR_get_error(), nullptr);
}
return(result == 1);
}