1 /*!
2  * \copyright Copyright (c) 2014-2021 Governikus GmbH & Co. KG, Germany
3  */
4 
5 #include "StateGetSelfAuthenticationData.h"
6 
7 #include "CertificateChecker.h"
8 #include "LogHandler.h"
9 #include "SelfAuthenticationData.h"
10 #include "TlsChecker.h"
11 
12 #include <http_parser.h>
13 #include <QLoggingCategory>
14 #include <QSslKey>
15 
16 Q_DECLARE_LOGGING_CATEGORY(network)
17 
18 using namespace governikus;
19 
StateGetSelfAuthenticationData(const QSharedPointer<WorkflowContext> & pContext)20 StateGetSelfAuthenticationData::StateGetSelfAuthenticationData(const QSharedPointer<WorkflowContext>& pContext)
21 	: AbstractState(pContext, false)
22 	, GenericContextContainer(pContext)
23 	, mReply()
24 {
25 }
26 
27 
run()28 void StateGetSelfAuthenticationData::run()
29 {
30 	Env::getSingleton<NetworkManager>()->clearConnections();
31 	QUrl address = getContext()->getRefreshUrl();
32 	qDebug() << address;
33 
34 	QNetworkRequest request(address);
35 	mReply.reset(Env::getSingleton<NetworkManager>()->get(request), &QObject::deleteLater);
36 	mConnections += connect(mReply.data(), &QNetworkReply::sslErrors, this, &StateGetSelfAuthenticationData::onSslErrors);
37 	mConnections += connect(mReply.data(), &QNetworkReply::encrypted, this, &StateGetSelfAuthenticationData::onSslHandshakeDone);
38 	mConnections += connect(mReply.data(), &QNetworkReply::finished, this, &StateGetSelfAuthenticationData::onNetworkReply);
39 }
40 
41 
reportCommunicationError(const GlobalStatus & pStatus)42 void StateGetSelfAuthenticationData::reportCommunicationError(const GlobalStatus& pStatus)
43 {
44 	qCritical() << pStatus;
45 	updateStatus(pStatus);
46 
47 	clearConnections();
48 	mReply->abort();
49 	Q_EMIT fireAbort();
50 }
51 
52 
checkSslConnectionAndSaveCertificate(const QSslConfiguration & pSslConfiguration)53 void StateGetSelfAuthenticationData::checkSslConnectionAndSaveCertificate(const QSslConfiguration& pSslConfiguration)
54 {
55 	const QSharedPointer<AuthContext>& context = getContext();
56 	Q_ASSERT(!context.isNull());
57 
58 	const auto& saveCertificateFunc = [&]
59 				(const QUrl& pUrl, const QSslCertificate& pCertificate)
60 			{
61 				context->addCertificateData(pUrl, pCertificate);
62 			};
63 
64 	GlobalStatus::ExternalInfoMap infoMap {
65 		{GlobalStatus::ExternalInformation::CERTIFICATE_ISSUER_NAME, TlsChecker::getCertificateIssuerName(pSslConfiguration.peerCertificate())}
66 	};
67 	if (!mReply.isNull())
68 	{
69 		infoMap.insert(GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString());
70 	}
71 
72 	switch (CertificateChecker::checkAndSaveCertificate(pSslConfiguration.peerCertificate(), getContext()->getRefreshUrl(), context->getDidAuthenticateEac1(), context->getDvCvc(), saveCertificateFunc))
73 	{
74 		case CertificateChecker::CertificateStatus::Good:
75 			break;
76 
77 		case CertificateChecker::CertificateStatus::Unsupported_Algorithm_Or_Length:
78 			reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Certificate_Unsupported_Algorithm_Or_Length, infoMap));
79 			return;
80 
81 		case CertificateChecker::CertificateStatus::Hash_Not_In_Description:
82 			reportCommunicationError(GlobalStatus(GlobalStatus::Code::Workflow_Network_Ssl_Hash_Not_In_Certificate_Description, infoMap));
83 			return;
84 	}
85 
86 	if (!TlsChecker::hasValidEphemeralKeyLength(pSslConfiguration.ephemeralServerKey()))
87 	{
88 		reportCommunicationError({GlobalStatus::Code::Workflow_Network_Ssl_Connection_Unsupported_Algorithm_Or_Length, infoMap});
89 	}
90 }
91 
92 
onSslErrors(const QList<QSslError> & pErrors)93 void StateGetSelfAuthenticationData::onSslErrors(const QList<QSslError>& pErrors)
94 {
95 	if (TlsChecker::containsFatalError(mReply, pErrors))
96 	{
97 		GlobalStatus::ExternalInfoMap infoMap;
98 		if (!mReply.isNull())
99 		{
100 			infoMap.insert(GlobalStatus::ExternalInformation::LAST_URL, mReply->url().toString());
101 		}
102 
103 		reportCommunicationError({GlobalStatus::Code::Network_Ssl_Establishment_Error, infoMap});
104 	}
105 }
106 
107 
onSslHandshakeDone()108 void StateGetSelfAuthenticationData::onSslHandshakeDone()
109 {
110 	const auto& cfg = mReply->sslConfiguration();
111 	TlsChecker::logSslConfig(cfg, spawnMessageLogger(network));
112 	checkSslConnectionAndSaveCertificate(cfg);
113 }
114 
115 
onNetworkReply()116 void StateGetSelfAuthenticationData::onNetworkReply()
117 {
118 	qCDebug(network) << "Received SelfAuthData";
119 	const auto statusCode = NetworkManager::getLoggedStatusCode(mReply, spawnMessageLogger(network));
120 
121 	if (statusCode == HTTP_STATUS_OK)
122 	{
123 		const SelfAuthenticationData data(mReply->readAll());
124 		if (data.isValid())
125 		{
126 			getContext()->setSelfAuthenticationData(data);
127 			Q_EMIT fireContinue();
128 		}
129 		else
130 		{
131 			qDebug() << "No valid data of self-authentication.";
132 			updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided);
133 			Q_EMIT fireAbort();
134 		}
135 	}
136 	else
137 	{
138 		qDebug() << "Could not read data for self-authentication.";
139 		updateStatus(GlobalStatus::Code::Workflow_Server_Incomplete_Information_Provided);
140 		Q_EMIT fireAbort();
141 	}
142 }
143 
144 
onExit(QEvent * pEvent)145 void StateGetSelfAuthenticationData::onExit(QEvent* pEvent)
146 {
147 	AbstractState::onExit(pEvent);
148 
149 	if (!mReply.isNull())
150 	{
151 		mReply.reset();
152 	}
153 }
154