1// Copyright (C) 2017 The Qt Company Ltd.
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 "qopen62541utils.h"
5#include <qopcuatype.h>
6#include "qopen62541valueconverter.h"
7
8#include <QtCore/qloggingcategory.h>
9#include <QtCore/qstringlist.h>
10#include <QtCore/quuid.h>
11
12#ifdef UA_ENABLE_ENCRYPTION
13#include <openssl/evp.h>
14#include <openssl/rsa.h>
15#endif
16
17#include <cstring>
18
19QT_BEGIN_NAMESPACE
20
21Q_DECLARE_LOGGING_CATEGORY(QT_OPCUA_PLUGINS_OPEN62541)
22
23UA_NodeId Open62541Utils::nodeIdFromQString(const QString &name)
24{
25 quint16 namespaceIndex;
26 QString identifierString;
27 char identifierType;
28 bool success = QOpcUa::nodeIdStringSplit(nodeIdString: name, nsIndex: &namespaceIndex, identifier: &identifierString, identifierType: &identifierType);
29
30 if (!success) {
31 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Failed to split node id string:" << name;
32 return UA_NODEID_NULL;
33 }
34
35 switch (identifierType) {
36 case 'i': {
37 bool isNumber;
38 uint identifier = identifierString.toUInt(ok: &isNumber);
39 if (isNumber && identifier <= ((std::numeric_limits<quint32>::max)()))
40 return UA_NODEID_NUMERIC(nsIndex: namespaceIndex, identifier: static_cast<UA_UInt32>(identifier));
41 else
42 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << name << "does not contain a valid numeric identifier";
43 break;
44 }
45 case 's': {
46 if (identifierString.size() > 0)
47 return UA_NODEID_STRING_ALLOC(nsIndex: namespaceIndex, chars: identifierString.toUtf8().constData());
48 else
49 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << name << "does not contain a valid string identifier";
50 break;
51 }
52 case 'g': {
53 QUuid uuid(identifierString);
54
55 if (uuid.isNull()) {
56 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << name << "does not contain a valid guid identifier";
57 break;
58 }
59
60 UA_Guid guid;
61 guid.data1 = uuid.data1;
62 guid.data2 = uuid.data2;
63 guid.data3 = uuid.data3;
64 std::memcpy(dest: guid.data4, src: uuid.data4, n: sizeof(uuid.data4));
65 return UA_NODEID_GUID(nsIndex: namespaceIndex, guid);
66 }
67 case 'b': {
68 const QByteArray temp = QByteArray::fromBase64(base64: identifierString.toLatin1());
69 if (temp.size() > 0) {
70 return UA_NODEID_BYTESTRING_ALLOC(nsIndex: namespaceIndex, chars: temp.constData());
71 }
72 else
73 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << name << "does not contain a valid byte string identifier";
74 break;
75 }
76 default:
77 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Could not parse node id:" << name;
78 }
79 return UA_NODEID_NULL;
80}
81
82QString Open62541Utils::nodeIdToQString(UA_NodeId id)
83{
84 QString result = QString::fromLatin1(ba: "ns=%1;").arg(a: id.namespaceIndex);
85
86 switch (id.identifierType) {
87 case UA_NODEIDTYPE_NUMERIC:
88 result.append(s: QString::fromLatin1(ba: "i=%1").arg(a: id.identifier.numeric));
89 break;
90 case UA_NODEIDTYPE_STRING:
91 result.append(s: QLatin1String("s="));
92 result.append(s: QString::fromUtf8(utf8: reinterpret_cast<char *>(id.identifier.string.data),
93 size: id.identifier.string.length));
94 break;
95 case UA_NODEIDTYPE_GUID: {
96 const UA_Guid &src = id.identifier.guid;
97 const QUuid uuid(src.data1, src.data2, src.data3, src.data4[0], src.data4[1], src.data4[2],
98 src.data4[3], src.data4[4], src.data4[5], src.data4[6], src.data4[7]);
99 result.append(QStringLiteral("g=")).append(v: QStringView(uuid.toString()).mid(pos: 1, n: 36)); // Remove enclosing {...}
100 break;
101 }
102 case UA_NODEIDTYPE_BYTESTRING: {
103 const QByteArray temp(reinterpret_cast<char *>(id.identifier.byteString.data), id.identifier.byteString.length);
104 result.append(QStringLiteral("b=")).append(s: temp.toBase64());
105 break;
106 }
107 default:
108 qCWarning(QT_OPCUA_PLUGINS_OPEN62541) << "Open62541 Utils: Could not convert UA_NodeId to QString";
109 result.clear();
110 }
111 return result;
112}
113
114void Open62541Utils::createEventFilter(const QOpcUaMonitoringParameters::EventFilter &filter, UA_ExtensionObject *out)
115{
116 UA_EventFilter *uaFilter = UA_EventFilter_new();
117 UA_EventFilter_init(p: uaFilter);
118 out->encoding = UA_EXTENSIONOBJECT_DECODED;
119 out->content.decoded.data = uaFilter;
120 out->content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];
121
122 QOpen62541ValueConverter::scalarFromQt<UA_EventFilter, QOpcUaMonitoringParameters::EventFilter>(var: filter, ptr: uaFilter);
123}
124
125#ifdef UA_ENABLE_ENCRYPTION
126bool Open62541Utils::checkSha1SignatureSupport()
127{
128 auto mdCtx = EVP_MD_CTX_create ();
129
130 if (!mdCtx)
131 return false;
132
133 auto pkCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
134
135 if (!pkCtx) {
136 EVP_MD_CTX_destroy(mdCtx);
137 return false;
138 }
139
140 auto ret = EVP_PKEY_keygen_init(ctx: pkCtx);
141
142 if (ret != 1) {
143 EVP_PKEY_CTX_free(ctx: pkCtx);
144 EVP_MD_CTX_destroy(mdCtx);
145 return false;
146 }
147
148 ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx: pkCtx, bits: 2048);
149
150 if (ret != 1) {
151 EVP_PKEY_CTX_free(ctx: pkCtx);
152 EVP_MD_CTX_destroy(mdCtx);
153 return false;
154 }
155
156 EVP_PKEY *pKey = nullptr;
157 ret = EVP_PKEY_keygen(ctx: pkCtx, ppkey: &pKey);
158
159 if (ret != 1) {
160 EVP_PKEY_CTX_free(ctx: pkCtx);
161 EVP_MD_CTX_destroy(mdCtx);
162 EVP_PKEY_free(pkey: pKey);
163 return false;
164 }
165
166 bool hasSupport = false;
167
168 ret = EVP_DigestSignInit (ctx: mdCtx, NULL, type: EVP_sha1(), NULL, pkey: pKey);
169 if (ret == 1)
170 hasSupport = true;
171
172 EVP_PKEY_CTX_free(ctx: pkCtx);
173 EVP_MD_CTX_destroy(mdCtx);
174 EVP_PKEY_free(pkey: pKey);
175
176 return hasSupport;
177}
178#endif
179
180QT_END_NAMESPACE
181

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtopcua/src/plugins/opcua/open62541/qopen62541utils.cpp