1// Copyright (C) 2018 Unified Automation GmbH
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qopcuapkiconfiguration.h"
5#include "qopcuaapplicationidentity.h"
6
7#include <QLoggingCategory>
8#include <QSslCertificate>
9#include <QSslCertificateExtension>
10
11QT_BEGIN_NAMESPACE
12
13Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_SECURITY);
14
15/*!
16 \class QOpcUaPkiConfiguration
17 \inmodule QtOpcUa
18 \brief QOpcUaPkiConfiguration defines the PKI configuration of the application.
19 \since QtOpcUa 5.13
20
21 This info must be configured using QOpcUaClient::setPkiConfiguration.
22 The used paths and files must be created beforehand.
23
24 \code
25 QOpcUaPkiConfiguration pkiConfig;
26 const QString pkiDir = QCoreApplication::applicationDirPath() + "/pki";
27
28 pkiConfig.setClientCertificateFile(pkiDir + "/own/certs/application.der");
29 pkiConfig.setPrivateKeyFile(pkiDir + "/own/private/application.pem");
30 pkiConfig.setTrustListDirectory(pkiDir + "/trusted/certs");
31 pkiConfig.setRevocationListDirectory(pkiDir + "/trusted/crl");
32 pkiConfig.setIssuerListDirectory(pkiDir + "/issuers/certs");
33 pkiConfig.setIssuerRevocationListDirectory(pkiDir + "/issuers/crl");
34
35 client->setPkiConfiguration(pkiConfig);
36 \endcode
37*/
38
39class QOpcUaPkiConfigurationData : public QSharedData
40{
41public:
42 QOpcUaPkiConfigurationData() {}
43
44 QString m_clientCertificateFile; /**< Own application certificate filename */
45 QString m_privateKeyFile; /**< Private key filename which belongs to m_certificateFile */
46 QString m_trustListDirectory; /**< Path to trust list directory */
47 QString m_revocationListDirectory; /**< Folder containing certificate revocation list */
48 QString m_issuerListDirectory; /**< Folder containing issuer intermediate certificates (untrusted) */
49 QString m_issuerRevocationListDirectory; /**< Folder containing issuer revocation list */
50};
51
52/*!
53 Default constructs a PKI configuration with no parameters set.
54*/
55QOpcUaPkiConfiguration::QOpcUaPkiConfiguration()
56 : data(new QOpcUaPkiConfigurationData())
57{}
58
59QOpcUaPkiConfiguration::~QOpcUaPkiConfiguration()
60{}
61
62/*!
63 Constructs a \l QOpcUaPkiConfiguration from \a other.
64*/
65QOpcUaPkiConfiguration::QOpcUaPkiConfiguration(const QOpcUaPkiConfiguration &other)
66 : data(other.data)
67{}
68
69/*!
70 Sets the values of \a rhs in this PKI configuration.
71*/
72QOpcUaPkiConfiguration &QOpcUaPkiConfiguration::operator=(const QOpcUaPkiConfiguration &rhs)
73{
74 if (this != &rhs)
75 data = rhs.data;
76 return *this;
77}
78
79/*!
80 Returns the file path of the application's client certificate.
81 */
82QString QOpcUaPkiConfiguration::clientCertificateFile() const
83{
84 return data->m_clientCertificateFile;
85}
86
87/*!
88 Sets the file path of the application's client certificate to \a value.
89
90 This file has to be in X509 DER format.
91*/
92void QOpcUaPkiConfiguration::setClientCertificateFile(const QString &value)
93{
94 data->m_clientCertificateFile = value;
95}
96
97/*!
98 Returns the file path of the application's private key.
99*/
100QString QOpcUaPkiConfiguration::privateKeyFile() const
101{
102 return data->m_privateKeyFile;
103}
104
105/*!
106 Sets the file path of the application's private key to \a value.
107
108 This file has to be in X509 PEM format.
109*/
110void QOpcUaPkiConfiguration::setPrivateKeyFile(const QString &value)
111{
112 data->m_privateKeyFile = value;
113}
114
115/*!
116 Returns the folder of the certificate trust list.
117*/
118QString QOpcUaPkiConfiguration::trustListDirectory() const
119{
120 return data->m_trustListDirectory;
121}
122
123/*!
124 Sets the path of the certificate trust list directory to \a value.
125
126 All certificates in this directory will be trusted.
127 Certificates have to be in X509 DER format.
128*/
129void QOpcUaPkiConfiguration::setTrustListDirectory(const QString &value)
130{
131 data->m_trustListDirectory = value;
132}
133
134/*!
135 Returns the path of the certificate revocation list directory.
136*/
137QString QOpcUaPkiConfiguration::revocationListDirectory() const
138{
139 return data->m_revocationListDirectory;
140}
141
142/*!
143 Sets the path of the certificate revocation list directory to \a value.
144*/
145void QOpcUaPkiConfiguration::setRevocationListDirectory(const QString &value)
146{
147 data->m_revocationListDirectory = value;
148}
149
150/*!
151 Returns the path of the intermediate issuer list directory.
152
153 These issuers will not be trusted.
154*/
155QString QOpcUaPkiConfiguration::issuerListDirectory() const
156{
157 return data->m_issuerListDirectory;
158}
159
160/*!
161 Sets the path of the intermediate issuer list directory to \a value.
162*/
163void QOpcUaPkiConfiguration::setIssuerListDirectory(const QString &value)
164{
165 data->m_issuerListDirectory = value;
166}
167
168/*!
169 Returns the path of the intermediate issuer revocation list directory.
170*/
171QString QOpcUaPkiConfiguration::issuerRevocationListDirectory() const
172{
173 return data->m_issuerRevocationListDirectory;
174}
175
176/*!
177 Sets the path of the intermediate issuer revocation list directory to \a value.
178*/
179void QOpcUaPkiConfiguration::setIssuerRevocationListDirectory(const QString &value)
180{
181 data->m_issuerRevocationListDirectory = value;
182}
183
184/*!
185 Returns an application identity based on the application's client certificate.
186
187 The application's identity has to match the used certificate. The returned application
188 identity is prefilled by using information of the configured client certificate.
189*/
190QOpcUaApplicationIdentity QOpcUaPkiConfiguration::applicationIdentity() const
191{
192 QOpcUaApplicationIdentity identity;
193
194 auto certList = QSslCertificate::fromPath(path: clientCertificateFile(), format: QSsl::Der);
195 if (certList.isEmpty()) {
196 qCWarning(QT_OPCUA_SECURITY) << "No client certificate found at" << clientCertificateFile()
197 << ". Application identity will be invalid.";
198 return QOpcUaApplicationIdentity();
199 }
200
201 auto extensions = certList[0].extensions();
202 for (const auto &extension : std::as_const(t&: extensions)) {
203 if (extension.name() == QLatin1String("subjectAltName")) { // OID: 2.5.29.17
204 const auto value = extension.value().toMap();
205 // const QString dns = value[QLatin1String("DNS")].toString();
206 const QString uri = value[QLatin1String("URI")].toString();
207
208 const auto token = uri.split(sep: QChar::fromLatin1(c: ':'), behavior: Qt::SkipEmptyParts);
209
210 if (token.size() != 4) {
211 qCWarning(QT_OPCUA_SECURITY) << "URI string from certificate has unexpected format:"
212 << uri << "Application identity will be invalid.";
213 return QOpcUaApplicationIdentity();
214 }
215
216 identity.setApplicationUri(uri);
217 identity.setApplicationName(token.at(i: 3));
218 identity.setProductUri(QStringLiteral("%1:%2").arg(args: token.at(i: 2), args: token.at(i: 3)));
219 }
220 }
221 return identity;
222}
223
224/*!
225 Return true if the public key information required to validate the server certificate
226 is set.
227*/
228bool QOpcUaPkiConfiguration::isPkiValid() const
229{
230 return !issuerListDirectory().isEmpty() &&
231 !issuerRevocationListDirectory().isEmpty() &&
232 !revocationListDirectory().isEmpty() &&
233 !trustListDirectory().isEmpty();
234}
235
236/*!
237 Returns true if the private key file and client certificate file are set.
238*/
239bool QOpcUaPkiConfiguration::isKeyAndCertificateFileSet() const
240{
241 return !clientCertificateFile().isEmpty() &&
242 !privateKeyFile().isEmpty();
243}
244
245QT_END_NAMESPACE
246

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtopcua/src/opcua/client/qopcuapkiconfiguration.cpp