1 /*!
2  * \copyright Copyright (c) 2014-2021 Governikus GmbH & Co. KG, Germany
3  */
4 
5 #include "CertificateDescription.h"
6 #include "KnownOIDs.h"
7 
8 #include <QCoreApplication>
9 #include <QDebug>
10 #include <QRegularExpression>
11 
12 
13 using namespace governikus;
14 
15 
16 namespace
17 {
takeWhileNonEmpty(const QStringList & lines)18 QStringList takeWhileNonEmpty(const QStringList& lines)
19 {
20 	QStringList result;
21 	for (const auto& line : lines)
22 	{
23 		const QString trimmedLine = line.trimmed();
24 		if (trimmedLine.isEmpty())
25 		{
26 			return result;
27 		}
28 		else
29 		{
30 			result += trimmedLine;
31 		}
32 	}
33 
34 	return result;
35 }
36 
37 
getField(const QString & pData,const QStringList & pSearchItems)38 QString getField(const QString& pData, const QStringList& pSearchItems)
39 {
40 	const QLatin1Char NEW_LINE('\n');
41 	const QRegularExpression REGEX_EMPTY_SECTION(QStringLiteral("^\\R{2,}"));
42 
43 	for (const auto& item : pSearchItems)
44 	{
45 		const auto pos = pData.indexOf(item);
46 		if (pos != -1)
47 		{
48 			const QString rest = pData.mid(pos + item.length());
49 			if (REGEX_EMPTY_SECTION.match(rest).hasMatch())
50 			{
51 				continue;
52 			}
53 
54 			const QStringList lines = takeWhileNonEmpty(rest.trimmed().split(NEW_LINE));
55 			if (lines.isEmpty())
56 			{
57 				continue;
58 			}
59 
60 			return lines.join(NEW_LINE);
61 		}
62 	}
63 
64 	return QString();
65 }
66 
67 
68 } // namespace
69 
70 
71 namespace governikus
72 {
73 
74 ASN1_SEQUENCE(CertificateDescription) = {
75 	ASN1_SIMPLE(CertificateDescription, mDescriptionType, ASN1_OBJECT),
76 	ASN1_EXP(CertificateDescription, mIssuerName, ASN1_UTF8STRING, 1),
77 	ASN1_EXP_OPT(CertificateDescription, mIssuerURL, ASN1_PRINTABLESTRING, 2),
78 	ASN1_EXP(CertificateDescription, mSubjectName, ASN1_UTF8STRING, 3),
79 	ASN1_EXP_OPT(CertificateDescription, mSubjectURL, ASN1_PRINTABLESTRING, 4),
80 	ASN1_EXP(CertificateDescription, mTermsOfUsage, ASN1_ANY, 5),
81 	ASN1_EXP_OPT(CertificateDescription, mRedirectURL, ASN1_PRINTABLESTRING, 6),
82 	ASN1_EXP_SET_OF_OPT(CertificateDescription, mCommCertificates, ASN1_OCTET_STRING, 7),
83 }
84 
85 
86 ASN1_SEQUENCE_END(CertificateDescription)
87 
88 IMPLEMENT_ASN1_FUNCTIONS(CertificateDescription)
89 IMPLEMENT_ASN1_OBJECT(CertificateDescription)
90 
91 } // namespace governikus
92 
93 
fromHex(const QByteArray & pHexValue)94 QSharedPointer<const CertificateDescription> CertificateDescription::fromHex(const QByteArray& pHexValue)
95 {
96 	return decode(QByteArray::fromHex(pHexValue));
97 }
98 
99 
decode(const QByteArray & pBytes)100 QSharedPointer<const CertificateDescription> CertificateDescription::decode(const QByteArray& pBytes)
101 {
102 	return decodeObject<CertificateDescription>(pBytes);
103 }
104 
105 
encode()106 QByteArray CertificateDescription::encode()
107 {
108 	return encodeObject(this);
109 }
110 
111 
setDescriptionType(const QByteArray & pOidAsText)112 void CertificateDescription::setDescriptionType(const QByteArray& pOidAsText)
113 {
114 	ASN1_OBJECT_free(mDescriptionType);
115 	mDescriptionType = Asn1ObjectUtil::parseFrom(pOidAsText);
116 }
117 
118 
getDescriptionType() const119 QByteArray CertificateDescription::getDescriptionType() const
120 {
121 	return Asn1ObjectUtil::convertTo(mDescriptionType);
122 }
123 
124 
setIssuerName(const QString & pIssuerName)125 void CertificateDescription::setIssuerName(const QString& pIssuerName)
126 {
127 	Asn1StringUtil::setValue(pIssuerName, mIssuerName);
128 }
129 
130 
getIssuerName() const131 QString CertificateDescription::getIssuerName() const
132 {
133 	return Asn1StringUtil::getValue(mIssuerName);
134 }
135 
136 
setIssuerUrl(const QString & pIssuerUrl)137 void CertificateDescription::setIssuerUrl(const QString& pIssuerUrl)
138 {
139 	if (mIssuerURL == nullptr)
140 	{
141 		mIssuerURL = ASN1_PRINTABLESTRING_new();
142 	}
143 	Asn1StringUtil::setValue(pIssuerUrl, mIssuerURL);
144 }
145 
146 
getIssuerUrl() const147 QString CertificateDescription::getIssuerUrl() const
148 {
149 	return Asn1StringUtil::getValue(mIssuerURL);
150 }
151 
152 
setSubjectName(const QString & pSubjectName)153 void CertificateDescription::setSubjectName(const QString& pSubjectName)
154 {
155 	Asn1StringUtil::setValue(pSubjectName, mSubjectName);
156 }
157 
158 
getSubjectName() const159 QString CertificateDescription::getSubjectName() const
160 {
161 	return Asn1StringUtil::getValue(mSubjectName);
162 }
163 
164 
setSubjectUrl(const QString & pSubjectUrl)165 void CertificateDescription::setSubjectUrl(const QString& pSubjectUrl)
166 {
167 	if (mSubjectURL == nullptr)
168 	{
169 		mSubjectURL = ASN1_PRINTABLESTRING_new();
170 	}
171 	Asn1StringUtil::setValue(pSubjectUrl, mSubjectURL);
172 }
173 
174 
getSubjectUrl() const175 QString CertificateDescription::getSubjectUrl() const
176 {
177 	return Asn1StringUtil::getValue(mSubjectURL);
178 }
179 
180 
getTermsOfUsageType() const181 CertificateDescription::TermsOfUsageType CertificateDescription::getTermsOfUsageType() const
182 {
183 	if (getDescriptionType() == KnownOIDs::TermsOfUsageType::ID_PLAIN_FORMAT)
184 	{
185 		return TermsOfUsageType::PLAIN_TEXT;
186 	}
187 	if (getDescriptionType() == KnownOIDs::TermsOfUsageType::ID_HTML_FORMAT)
188 	{
189 		return TermsOfUsageType::HTML;
190 	}
191 	return TermsOfUsageType::PDF;
192 }
193 
194 
getTermsOfUsage() const195 QString CertificateDescription::getTermsOfUsage() const
196 {
197 	QString string;
198 	if (mTermsOfUsage->type == V_ASN1_UTF8STRING)
199 	{
200 		string = Asn1StringUtil::getValue(mTermsOfUsage->value.utf8string);
201 	}
202 	else if (mTermsOfUsage->type == V_ASN1_IA5STRING)
203 	{
204 		string = Asn1StringUtil::getValue(mTermsOfUsage->value.ia5string);
205 	}
206 	else if (mTermsOfUsage->type == V_ASN1_OCTET_STRING && mTermsOfUsage->value.octet_string != nullptr)
207 	{
208 		string = QString::fromLatin1(Asn1TypeUtil::encode(mTermsOfUsage).toHex().toUpper());
209 	}
210 
211 	return string;
212 }
213 
214 
setRedirectUrl(const QString & pRedirectUrl)215 void CertificateDescription::setRedirectUrl(const QString& pRedirectUrl)
216 {
217 	if (mRedirectURL == nullptr)
218 	{
219 		mRedirectURL = ASN1_PRINTABLESTRING_new();
220 	}
221 	Asn1StringUtil::setValue(pRedirectUrl, mRedirectURL);
222 }
223 
224 
getRedirectUrl() const225 QString CertificateDescription::getRedirectUrl() const
226 {
227 	return Asn1StringUtil::getValue(mRedirectURL);
228 }
229 
230 
getCommCertificates() const231 QSet<QString> CertificateDescription::getCommCertificates() const
232 {
233 	QSet<QString> commCerts;
234 	if (mCommCertificates != nullptr)
235 	{
236 		const auto size = sk_ASN1_OCTET_STRING_num(mCommCertificates);
237 		commCerts.reserve(size);
238 		for (int i = 0; i < size; i++)
239 		{
240 			const ASN1_OCTET_STRING* octetString = sk_ASN1_OCTET_STRING_value(mCommCertificates, i);
241 			QByteArray byteBuf(reinterpret_cast<char*>(octetString->data), octetString->length);
242 			commCerts += QString::fromLatin1(byteBuf.toHex().toUpper());
243 		}
244 	}
245 	return commCerts;
246 }
247 
248 
getServiceProviderAddress() const249 QString CertificateDescription::getServiceProviderAddress() const
250 {
251 	static const QStringList SEARCH_ITEMS({
252 				QStringLiteral("Name, Anschrift und E-Mail-Adresse des Diensteanbieters:")
253 			});
254 
255 	return getField(getTermsOfUsage(), SEARCH_ITEMS);
256 }
257 
258 
getPurpose() const259 QString CertificateDescription::getPurpose() const
260 {
261 	static const QStringList SEARCH_ITEMS({
262 				QStringLiteral("Gesch\u00E4ftszweck:"),
263 				QStringLiteral("Zweck des Auslesevorgangs:"),
264 				QStringLiteral("Verwendung der Daten:"),
265 				QStringLiteral("Zweck der Daten\u00FCbermittlung:")
266 			});
267 
268 	return getField(getTermsOfUsage(), SEARCH_ITEMS);
269 }
270 
271 
getDataSecurityOfficer() const272 QString CertificateDescription::getDataSecurityOfficer() const
273 {
274 	static const QStringList SEARCH_ITEMS({QStringLiteral(
275 			"Hinweis auf die f\u00FCr den Diensteanbieter zust\u00E4ndigen Stellen, "
276 			"die die Einhaltung der Vorschriften zum Datenschutz kontrollieren:")});
277 
278 	return getField(getTermsOfUsage(), SEARCH_ITEMS);
279 }
280