Coverage Report

Created: 2026-10-05 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/ua_securechannel.h
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2017 (c) Florian Palm
7
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
8
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
9
 */
10
11
#ifndef UA_SECURECHANNEL_H_
12
#define UA_SECURECHANNEL_H_
13
14
struct UA_SecureChannel;
15
typedef struct UA_SecureChannel UA_SecureChannel;
16
17
#include <open62541/util.h>
18
#include <open62541/types.h>
19
#include <open62541/plugin/log.h>
20
#include <open62541/plugin/securitypolicy.h>
21
#include <open62541/plugin/eventloop.h>
22
#include <open62541/transport_generated.h>
23
24
#include "open62541_queue.h"
25
#include "util/ua_util_internal.h"
26
27
_UA_BEGIN_DECLS
28
29
/* True for the ECC SecurityPolicy family, including the AEAD variants
30
 * (ECC_nistP256_AesGcm/ChaChaPoly, ECC_curve25519/448). Use this instead of
31
 * spelling out the policyType enum pair at each call site. */
32
static UA_INLINE UA_Boolean
33
0
UA_SecurityPolicy_isEcc(const UA_SecurityPolicy *policy) {
34
0
    return policy != NULL &&
35
0
        (policy->policyType == UA_SECURITYPOLICYTYPE_ECC ||
36
0
         policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD);
37
0
}
Unexecuted instantiation: ua_types.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_types_definition.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_types_encoding_binary.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_util.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_types_lex.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_encryptedsecret.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_securechannel.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_securechannel_crypto.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_session.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_nodes.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_ns0.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_ns0_diagnostics.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_ns0_gds.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_config.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_binary.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_utils.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_server_async.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_subscription.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_subscription_datachange.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_subscription_event.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_subscription_alarms_conditions.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_view.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_method.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_session.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_attribute.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_discovery.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_subscription.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_monitoreditem.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_securechannel.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_services_nodemanagement.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client_connect.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client_discovery.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client_highlevel.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client_subscriptions.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_client_util.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_eventfilter_parser.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_eventfilter_lex.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_eventfilter_grammar.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_types_encoding_json_105.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_networkmessage_json.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_networkmessage_binary.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_connection.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_dataset.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_writer.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_writergroup.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_reader.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_readergroup.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_manager.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_ns0.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_pubsub_ns0_sks.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_types_encoding_xml.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_discovery_mdns.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: ua_discovery.c:UA_SecurityPolicy_isEcc
Unexecuted instantiation: fuzz_server_services.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_client.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_tcp_message.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_msg_message.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_opn_message.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_process_request.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_binary_message.cc:UA_SecurityPolicy_isEcc(UA_SecurityPolicy const*)
38
39
/* True for AEAD SecurityPolicies (AES-GCM / ChaCha20-Poly1305). These derive a
40
 * combined encryption key + IV (no separate signing key) and authenticate via
41
 * the cipher tag; the SecureChannel and EccEncryptedSecret code use this to
42
 * switch on the AEAD message layout. */
43
static UA_INLINE UA_Boolean
44
0
UA_SecurityPolicy_isAead(const UA_SecurityPolicy *policy) {
45
0
    return policy != NULL && policy->policyType == UA_SECURITYPOLICYTYPE_ECC_AEAD;
46
0
}
Unexecuted instantiation: ua_types.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_types_definition.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_types_encoding_binary.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_util.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_types_lex.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_encryptedsecret.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_securechannel.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_securechannel_crypto.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_session.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_nodes.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_ns0.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_ns0_diagnostics.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_ns0_gds.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_config.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_binary.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_utils.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_server_async.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_subscription.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_subscription_datachange.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_subscription_event.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_subscription_alarms_conditions.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_view.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_method.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_session.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_attribute.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_discovery.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_subscription.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_monitoreditem.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_securechannel.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_services_nodemanagement.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client_connect.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client_discovery.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client_highlevel.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client_subscriptions.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_client_util.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_eventfilter_parser.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_eventfilter_lex.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_eventfilter_grammar.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_types_encoding_json_105.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_networkmessage_json.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_networkmessage_binary.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_connection.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_dataset.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_writer.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_writergroup.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_reader.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_readergroup.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_manager.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_ns0.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_pubsub_ns0_sks.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_types_encoding_xml.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_discovery_mdns.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: ua_discovery.c:UA_SecurityPolicy_isAead
Unexecuted instantiation: fuzz_server_services.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_client.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_tcp_message.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_msg_message.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_opn_message.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_process_request.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
Unexecuted instantiation: fuzz_binary_message.cc:UA_SecurityPolicy_isAead(UA_SecurityPolicy const*)
47
48
/* Forward-Declaration so the SecureChannel can point to a singly-linked list of
49
 * Sessions. This is only used in the server, not in the client. */
50
struct UA_Session;
51
typedef struct UA_Session UA_Session;
52
53
/* The message header of the OPC UA binary protocol is structured as follows:
54
 *
55
 * - MessageType (3 Byte)
56
 * - IsFinal (1 Byte)
57
 * - MessageSize (4 Byte)
58
 * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH ***
59
 * - SecureChannelId (4 Byte)
60
 * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH ***
61
 * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length)
62
 * - SequenceHeader (8 Byte)
63
 *   - SequenceNumber
64
 *   - RequestId
65
 */
66
67
5.40k
#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8
68
0
#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12
69
0
#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4
70
0
#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8
71
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \
72
0
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +                \
73
0
     UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH)
74
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH   \
75
0
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +            \
76
0
    UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH +  \
77
0
     UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH)
78
79
/* Minimum length of a valid message (ERR message with an empty reason) */
80
2.27k
#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16
81
82
/* For chunked requests */
83
typedef struct UA_Chunk {
84
    TAILQ_ENTRY(UA_Chunk) pointers;
85
    UA_ByteString bytes;
86
    UA_MessageType messageType;
87
    UA_ChunkType chunkType;
88
    UA_UInt32 requestId;
89
    UA_Boolean copied; /* Do the bytes point to a buffer from the network or was
90
                        * memory allocated for the chunk separately */
91
} UA_Chunk;
92
93
typedef TAILQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue;
94
95
typedef enum {
96
    UA_SECURECHANNELRENEWSTATE_NORMAL,
97
98
    /* Client has sent an OPN, but not received a response so far. */
99
    UA_SECURECHANNELRENEWSTATE_SENT,
100
101
    /* The server waits for the first request with the new token for the rollover.
102
     * The new token is stored in the altSecurityToken. The configured local and
103
     * remote symmetric encryption keys are the old ones. */
104
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER,
105
106
    /* The client already uses the new token. But he waits for the server to respond
107
     * with the new token to complete the rollover. The old token is stored in
108
     * altSecurityToken. The local symmetric encryption key is new. The remote
109
     * encryption key is the old one. */
110
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT
111
} UA_SecureChannelRenewState;
112
113
struct UA_SecureChannel {
114
    UA_SecureChannelState state;
115
    UA_SecureChannelRenewState renewState;
116
    UA_MessageSecurityMode securityMode;
117
    UA_ShutdownReason shutdownReason;
118
119
    UA_ConnectionConfig config;
120
    UA_String endpointUrl;
121
    UA_String remoteAddress;
122
123
    /* Connection handling in the EventLoop */
124
    UA_ConnectionManager *connectionManager;
125
    uintptr_t connectionId;
126
127
    /* The namespace mapping translates namespace indices of NodeIds during
128
     * de/encoding (client only) */
129
    UA_NamespaceMapping *namespaceMapping;
130
131
    /* Linked lists (only used in the server) */
132
    TAILQ_ENTRY(UA_SecureChannel) serverEntry;
133
    TAILQ_ENTRY(UA_SecureChannel) componentEntry;
134
135
    /* Rules for revolving the token with a renew OPN request: The client is
136
     * allowed to accept messages with the old token until the OPN response has
137
     * arrived. The server accepts the old token until one message secured with
138
     * the new token has arrived.
139
     *
140
     * We recognize whether nextSecurityToken contains a valid next token if the
141
     * ChannelId is not 0. */
142
    UA_ChannelSecurityToken securityToken;    /* Also contains the channelId */
143
    UA_ChannelSecurityToken altSecurityToken; /* Alternative token for the rollover.
144
                                               * See the renewState. */
145
146
    /* The endpoint and context of the channel */
147
    UA_SecurityPolicy *securityPolicy;
148
    void *channelContext; /* For interaction with the security policy */
149
150
    /* Properties derived from the SecurityPolicy URI, cached when the policy is
151
     * set (it is fixed for the channel's lifetime). This avoids re-evaluating
152
     * UA_SecurityPolicy_isEnhancedSecurity / _useLegacySequenceNumbers (which
153
     * scan the policy URI) on the per-chunk send and receive paths. */
154
    UA_Boolean enhancedSecurity;      /* UA_SecurityPolicy_isEnhancedSecurity */
155
    UA_Boolean legacySequenceNumbers; /* UA_SecurityPolicy_useLegacySequenceNumbers */
156
157
    /* OPC UA Part 6 v1.05.07 §6.7.5 "ChannelThumbprint" for
158
     * SecurityPolicies with secureChannelEnhancements = true.
159
     * The first OPN request signature is appended to the data signed by
160
     * the OPN response (and vice versa). Set on send, consumed on
161
     * receive, then cleared. Never used on OPN renewals. */
162
    UA_ByteString firstRequestSignature;
163
164
    /* OPC UA Part 6 v1.05.07 §6.8.1 step 2 "Extract" IKM chaining
165
     * accumulator for SecurityPolicies with secureChannelEnhancements =
166
     * true. The IKM is the size of the policy's shared secret (e.g. 32
167
     * bytes for P-256). On each renewal, the policy's generateKey
168
     * wrapper XORs the new shared secret with this value and writes the
169
     * result back. The SecureChannel passes this value as a prefix of
170
     * the `secret` ByteString to the policy's generateKey, where the
171
     * policy strips and updates it. Zero-length on the first OPN. */
172
    UA_ByteString currentIKM;
173
174
    /* OPC UA Part 6 v1.05.07 ChannelThumbprint: the (verified) signature
175
     * of the first OpenSecureChannel *response*. Captured once on the
176
     * first OPN (client: on response verify; server: on response sign)
177
     * and preserved across renewals. Used to bind the CreateSession /
178
     * ActivateSession SignatureData to this SecureChannel. Only set for
179
     * SecurityPolicies with secureChannelEnhancements = true. */
180
    UA_ByteString channelThumbprint;
181
182
    /* Asymmetric encryption info */
183
    UA_ByteString remoteCertificate;
184
    UA_Byte remoteCertificateThumbprint[20]; /* The thumbprint of the remote certificate */
185
186
    /* Symmetric encryption nonces. These are used to generate the key material
187
     * and must not be reused once the keys are in place.
188
     *
189
     * Nonces are also used during the CreateSession / ActivateSession
190
     * handshake. These are not handled here, as the Session handling can
191
     * overlap with a RenewSecureChannel. */
192
    UA_ByteString remoteNonce;
193
    UA_ByteString localNonce;
194
195
    UA_UInt32 receiveSequenceNumber;
196
    UA_UInt32 sendSequenceNumber;
197
198
    /* Sessions that are bound to the SecureChannel (singly-linked list, only
199
     * used in the server) */
200
    UA_Session *sessions;
201
202
    /* (Decrypted) chunks waiting to be processed */
203
    UA_ChunkQueue chunks;
204
    size_t chunksCount;
205
    size_t chunksLength;
206
207
    /* Received buffer from which no chunks have been extracted so far */
208
    UA_ByteString unprocessed;
209
    size_t unprocessedOffset;
210
    UA_Boolean unprocessedCopied;
211
    UA_DelayedCallback unprocessedDelayed;
212
213
    void *processOPNHeaderApplication;
214
    UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel,
215
                                      const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
216
};
217
218
void UA_SecureChannel_init(UA_SecureChannel *channel);
219
220
/* Trigger the shutdown */
221
void UA_SecureChannel_shutdown(UA_SecureChannel *channel,
222
                               UA_ShutdownReason shutdownReason);
223
224
/* Eventual cleanup after the channel has closed. It is possible to call _init
225
 * on the channel afterwards to reset it to the fresh status. */
226
void UA_SecureChannel_clear(UA_SecureChannel *channel);
227
228
/* Process the remote configuration in the HEL/ACK handshake. The connection
229
 * config is initialized with the local settings. */
230
UA_StatusCode
231
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
232
                               const UA_TcpAcknowledgeMessage *remoteConfig);
233
234
UA_StatusCode
235
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel,
236
                                   UA_SecurityPolicy *securityPolicy,
237
                                   const UA_ByteString *remoteCertificate);
238
239
UA_StatusCode
240
UA_SecureChannel_setSecurityMode(UA_SecureChannel *channel,
241
                                 UA_MessageSecurityMode securityMode);
242
243
UA_Boolean
244
UA_SecureChannel_isConnected(UA_SecureChannel *channel);
245
246
/* Returns true if the channel has timed out. Performs the SecurityToken
247
 * rollover if required and possible. */
248
UA_Boolean
249
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel,
250
                              UA_DateTime nowMonotonic);
251
252
/* Remove (partially) received unprocessed chunks */
253
void
254
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel);
255
256
/* Wrapper function for generating a local nonce for the supplied channel. Uses
257
 * the random generator of the channels security policy to allocate and generate
258
 * a nonce with the specified length. */
259
UA_StatusCode
260
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel);
261
262
UA_StatusCode
263
UA_SecureChannel_generateLocalKeys(UA_SecureChannel *channel);
264
265
UA_StatusCode
266
generateRemoteKeys(UA_SecureChannel *channel);
267
268
/* OPC UA Part 6 v1.05.07 (secureChannelEnhancements): build the
269
 * channel-bound CreateSession ServerSignature data
270
 *   channelThumbprint | clientNonce | H(serverChannelCert) |
271
 *   H(clientChannelCert) | serverNonce
272
 * Both the server (sign) and client (verify) call this with the same
273
 * logical values. `out` is allocated by the callee. */
274
UA_StatusCode
275
UA_SecureChannel_buildCreateSessionSignatureData(
276
    const UA_SecureChannel *channel, const UA_ByteString *clientNonce,
277
    const UA_ByteString *serverNonce, const UA_ByteString *serverChannelCert,
278
    const UA_ByteString *clientChannelCert, UA_ByteString *out);
279
280
/* OPC UA Part 6 v1.05.07: build the channel-bound ActivateSession
281
 * ClientSignature data
282
 *   channelThumbprint | serverNonce | H(serverAppCert) |
283
 *   H(serverChannelCert) | H(clientChannelCert) | clientNonce
284
 * `out` is allocated by the callee. */
285
UA_StatusCode
286
UA_SecureChannel_buildActivateSessionSignatureData(
287
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
288
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
289
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientChannelCert,
290
    UA_ByteString *out);
291
292
/* OPC UA Part 6 v1.05.07: build the channel-bound ActivateSession
293
 * user-token (X.509) signature data
294
 *   channelThumbprint | serverNonce | H(serverAppCert) | H(serverChannelCert) |
295
 *   H(clientAppCert) | H(clientChannelCert) | clientNonce
296
 * This is the ClientSignature layout with an extra H(clientAppCert) - the
297
 * CLIENT's APPLICATION instance certificate - inserted before
298
 * H(clientChannelCert). NOTE: the user/X509-token certificate does NOT appear
299
 * in the signed data (it is conveyed and validated separately); the signature
300
 * only proves possession of the user key over the channel-bound data. */
301
UA_StatusCode
302
UA_SecureChannel_buildUserTokenSignatureData(
303
    const UA_SecureChannel *channel, const UA_ByteString *serverNonce,
304
    const UA_ByteString *clientNonce, const UA_ByteString *serverAppCert,
305
    const UA_ByteString *serverChannelCert, const UA_ByteString *clientAppCert,
306
    const UA_ByteString *clientChannelCert, UA_ByteString *out);
307
308
/**
309
 * Sending Messages
310
 * ---------------- */
311
312
/* When a fatal error occurs the Server shall send an Error Message to the
313
 * Client and close the socket. When a Client encounters one of these errors, it
314
 * shall also close the socket but does not send an Error Message. After the
315
 * socket is closed a Client shall try to reconnect automatically using the
316
 * mechanisms described in [...]. */
317
void
318
UA_SecureChannel_sendERR(UA_SecureChannel *channel, UA_TcpErrorMessage *error);
319
320
UA_StatusCode
321
UA_SecureChannel_sendOPN(UA_SecureChannel *channel, UA_UInt32 requestId,
322
                         const void *content, const UA_DataType *contentType);
323
324
UA_StatusCode
325
UA_SecureChannel_sendMSG(UA_SecureChannel *channel, UA_UInt32 requestId,
326
                         void *payload, const UA_DataType *payloadType);
327
328
UA_StatusCode
329
UA_SecureChannel_sendCLO(UA_SecureChannel *channel, UA_UInt32 requestId,
330
                         UA_CloseSecureChannelRequest *req);
331
332
/* The MessageContext is forwarded into the encoding layer so that we can send
333
 * chunks before continuing to encode. This lets us reuse a fixed chunk-sized
334
 * messages buffer. */
335
typedef struct {
336
    UA_SecureChannel *channel;
337
    UA_UInt32 requestId;
338
    UA_UInt32 messageType;
339
340
    UA_UInt16 chunksSoFar;
341
    size_t messageSizeSoFar;
342
343
    UA_ByteString messageBuffer;
344
    UA_Byte *buf_pos;
345
    const UA_Byte *buf_end;
346
347
    UA_Boolean final;
348
} UA_MessageContext;
349
350
/* Start the context of a new symmetric message. */
351
UA_StatusCode
352
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
353
                        UA_UInt32 requestId, UA_MessageType messageType);
354
355
/* Encode the content and send out full chunks. If the return code is good, then
356
 * the ChunkInfo contains encoded content that has not been sent. If the return
357
 * code is bad, then the ChunkInfo has been cleaned up internally. */
358
UA_StatusCode
359
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
360
                         const UA_DataType *contentType);
361
362
/* Sends a symmetric message already encoded in the context. The context is
363
 * cleaned up, also in case of errors. */
364
UA_StatusCode
365
UA_MessageContext_finish(UA_MessageContext *mc);
366
367
/* To be used when a failure occures when a MessageContext is open. Note that
368
 * the _encode and _finish methods will clean up internally. _abort can be run
369
 * on a MessageContext that has already been cleaned up before. */
370
void
371
UA_MessageContext_abort(UA_MessageContext *mc);
372
373
/**
374
 * Receive Message
375
 * --------------- */
376
377
/* Process a received buffer. This always has these three steps:
378
 *
379
 * 1. loadBuffer: The chunks in the SecureChannel are cut into chunks.
380
 *    The chunks can still point to the buffer.
381
 * 2. getCompleteMessage: Assemble chunks into a complete message. This is
382
 *    repeated until an error occours or an empty message is returned.
383
 * 3. persistBuffer: Make a copy of the remaining unpprocessed bytestring. So
384
 *    that the NetworkManager can reuse or free the packet memory.
385
 *
386
 * Note that only MSG and CLO messages are decrypted. HEL/ACK/OPN/... are
387
 * forwarded verbatim to the application. */
388
UA_StatusCode
389
UA_SecureChannel_loadBuffer(UA_SecureChannel *channel, const UA_ByteString buffer);
390
391
UA_StatusCode
392
UA_SecureChannel_getCompleteMessage(UA_SecureChannel *channel,
393
                                    UA_MessageType *messageType, UA_UInt32 *requestId,
394
                                    UA_ByteString *payload, UA_Boolean *copied,
395
                                    UA_DateTime nowMonotonic);
396
397
UA_StatusCode
398
UA_SecureChannel_persistBuffer(UA_SecureChannel *channel);
399
400
/* Internal methods in ua_securechannel_crypto.h */
401
402
UA_StatusCode
403
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
404
              const UA_Byte **buf_end);
405
406
/* Decrypt and verify via the signature. The chunk buffer is reused to hold the
407
 * decrypted data after the MessageHeader and SecurityHeader. The chunk length
408
 * is reduced by the signature, padding and encryption overhead.
409
 *
410
 * The offset argument points to the start of the encrypted content (beginning
411
 * with the SequenceHeader).*/
412
UA_StatusCode
413
decryptAndVerifyChunk(UA_SecureChannel *channel,
414
                      const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
415
                      const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
416
                      UA_MessageType messageType, UA_ByteString *chunk, size_t offset);
417
418
size_t
419
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel);
420
421
UA_StatusCode
422
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
423
                   const UA_Byte *buf_end, size_t totalLength,
424
                   size_t securityHeaderLength, UA_UInt32 requestId,
425
                   size_t *const finalLength);
426
427
/* Advance and return the next SequenceNumber to put into an outgoing chunk
428
 * (asymmetric OPN and symmetric MSG/CLO alike). Part 6 §6.7.2.4: the legacy
429
 * policies start at 1 and roll over to 1; the v1.05.07 enhanced/ECC policies
430
 * (LegacySequenceNumbers = false) start at 0 and roll over to 0. */
431
UA_UInt32
432
UA_SecureChannel_nextSequenceNumber(UA_SecureChannel *channel);
433
434
void
435
setBufPos(UA_MessageContext *mc);
436
437
UA_StatusCode
438
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
439
               UA_DateTime nowMonotonic);
440
441
UA_StatusCode
442
checkAsymHeader(UA_SecureChannel *channel,
443
                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
444
445
void
446
padChunk(UA_SecureChannel *channel,
447
         const UA_SecurityPolicySignatureAlgorithm *signatureAlgorithm,
448
         const UA_SecurityPolicyEncryptionAlgorithm *encryptionAlgorithm,
449
         const UA_Byte *start, UA_Byte **pos);
450
451
UA_StatusCode
452
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
453
                   UA_ByteString *buf, size_t securityHeaderLength,
454
                   size_t totalLength);
455
456
UA_StatusCode
457
signAndEncryptSym(UA_MessageContext *messageContext,
458
                  size_t preSigLength, size_t totalLength);
459
460
/**
461
 * Log Helper
462
 * ----------
463
 * C99 requires at least one element for the variadic argument. If the log
464
 * statement has no variable arguments, supply an additional NULL. It will be
465
 * ignored by printf.
466
 *
467
 * We have to jump through some hoops to enable the use of format strings
468
 * without arguments since (pedantic) C99 does not allow variadic macros with
469
 * zero arguments. So we add a dummy argument that is not printed (%.0s is
470
 * string of length zero). */
471
472
#define UA_LOG_CHANNEL_INTERNAL(LOGGER, LEVEL, CHANNEL, MSG, ...)       \
473
    do {                                                                \
474
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
475
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL,            \
476
                       "TCP %lu\t| SC %" PRIu32 "\t| " MSG "%.0s", \
477
                       (long unsigned)(CHANNEL)->connectionId,          \
478
                       (CHANNEL)->securityToken.channelId, __VA_ARGS__); \
479
    } \
480
    } while (0)
481
482
#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...)                      \
483
334
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, TRACE, CHANNEL, __VA_ARGS__, ""))
484
#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...)                      \
485
4.10k
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, DEBUG, CHANNEL, __VA_ARGS__, ""))
486
#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...)                       \
487
2.27k
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, INFO, CHANNEL, __VA_ARGS__, ""))
488
#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...)                    \
489
847
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, WARNING, CHANNEL, __VA_ARGS__, ""))
490
#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...)                      \
491
106
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, ERROR, CHANNEL, __VA_ARGS__, ""))
492
#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...)                      \
493
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, FATAL, CHANNEL, __VA_ARGS__, ""))
494
495
_UA_END_DECLS
496
497
#endif /* UA_SECURECHANNEL_H_ */