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