Coverage Report

Created: 2026-10-03 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/ua_securechannel.c
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 2014, 2016-2017 (c) Florian Palm
7
 *    Copyright 2015-2016 (c) Sten GrĂ¼ner
8
 *    Copyright 2015 (c) Oleksiy Vasylyev
9
 *    Copyright 2016 (c) TorbenD
10
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
11
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
12
 *    Copyright 2018-2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
13
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
14
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
15
 */
16
17
#include <open62541/types.h>
18
#include <open62541/transport_generated.h>
19
20
#include "ua_securechannel.h"
21
#include "ua_types_encoding_binary.h"
22
23
4.43k
#define UA_BITMASK_MESSAGETYPE 0x00ffffffu
24
4.43k
#define UA_BITMASK_CHUNKTYPE 0xff000000u
25
26
const UA_String UA_SECURITY_POLICY_NONE_URI =
27
    {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"};
28
29
void
30
13.1k
UA_SecureChannel_init(UA_SecureChannel *channel) {
31
    /* Normal linked lists are initialized by zeroing out */
32
13.1k
    memset(channel, 0, sizeof(UA_SecureChannel));
33
13.1k
    TAILQ_INIT(&channel->chunks);
34
13.1k
}
35
36
UA_StatusCode
37
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, UA_SecurityPolicy *sp,
38
3.26k
                                   const UA_ByteString *remoteCertificate) {
39
    /* Is a policy already configured? */
40
3.26k
    UA_CHECK_ERROR(!channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR,
41
3.26k
                   sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
42
3.26k
                   "Security policy already configured");
43
44
    /* Create the context */
45
3.26k
    UA_StatusCode res = sp->newChannelContext(sp, remoteCertificate,
46
3.26k
                                              &channel->channelContext);
47
3.26k
    res |= UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate);
48
3.26k
    UA_CHECK_STATUS_ERROR(res, return res, sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
49
3.26k
                          "Could not set up the SecureChannel context");
50
51
    /* Compute the certificate thumbprint */
52
3.26k
    UA_ByteString remoteCertificateThumbprint =
53
3.26k
        {20, channel->remoteCertificateThumbprint};
54
3.26k
    res = sp->makeCertThumbprint(sp, &channel->remoteCertificate,
55
3.26k
                                 &remoteCertificateThumbprint);
56
3.26k
    UA_CHECK_STATUS_ERROR(res, return res, sp->logger, UA_LOGCATEGORY_SECURITYPOLICY,
57
3.26k
                          "Could not create the certificate thumbprint");
58
59
    /* Set the SecurityPolicy and cache the URI-derived properties (the policy
60
     * is fixed for the channel's lifetime). */
61
3.26k
    channel->securityPolicy = sp;
62
3.26k
    channel->enhancedSecurity = UA_SecurityPolicy_isEnhancedSecurity(sp);
63
3.26k
    channel->legacySequenceNumbers = UA_SecurityPolicy_useLegacySequenceNumbers(sp);
64
65
    /* Set a temporary SecurityMode. The client sets the final SecurityMode
66
     * right after. The server only after fully decoding the OPN message in the
67
     * OpenSecureChannel service. But we need the SecurityMode for decoding. The
68
     * OPN message is always signed and encrypted when not #None. */
69
3.26k
    if(sp->policyType == UA_SECURITYPOLICYTYPE_NONE)
70
3.26k
        channel->securityMode = UA_MESSAGESECURITYMODE_NONE;
71
0
    else
72
0
        channel->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
73
3.26k
    return UA_STATUSCODE_GOOD;
74
3.26k
}
75
76
/* The #None SecurityPolicy must use the NONE SecurityMode. All other
77
 * SecurityPolicies must not. */
78
UA_StatusCode
79
UA_SecureChannel_setSecurityMode(UA_SecureChannel *channel,
80
463
                                 UA_MessageSecurityMode securityMode) {
81
463
    if(securityMode == UA_MESSAGESECURITYMODE_INVALID ||
82
441
       (UA_UInt32)securityMode > UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
83
22
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
84
441
    UA_SecurityPolicy *sp = channel->securityPolicy;
85
441
    if(!sp)
86
0
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
87
441
    UA_Boolean isNonePolicy = (sp->policyType == UA_SECURITYPOLICYTYPE_NONE);
88
441
    UA_Boolean isNoneMode = (securityMode == UA_MESSAGESECURITYMODE_NONE);
89
441
    if(isNonePolicy != isNoneMode)
90
1
        return UA_STATUSCODE_BADSECURITYMODEREJECTED;
91
440
    channel->securityMode = securityMode;
92
440
    return UA_STATUSCODE_GOOD;
93
441
}
94
95
/* Hides some errors before sending them to a client according to the
96
 * standard. */
97
static void
98
1.76k
hideErrors(UA_TcpErrorMessage *const error) {
99
1.76k
    switch(error->error) {
100
0
    case UA_STATUSCODE_BADCERTIFICATEINVALID:
101
0
    case UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE:
102
0
    case UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED:
103
0
    case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED:
104
0
    case UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN:
105
0
    case UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN:
106
0
    case UA_STATUSCODE_BADCERTIFICATEREVOKED:
107
0
    case UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED:
108
0
    case UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED:
109
0
        error->error = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
110
0
        error->reason = UA_STRING_NULL;
111
0
        break;
112
        // TODO: Check if these are all cases that need to be covered.
113
1.76k
    default:
114
1.76k
        break;
115
1.76k
    }
116
1.76k
}
117
118
UA_Boolean
119
7.25k
UA_SecureChannel_isConnected(UA_SecureChannel *channel) {
120
7.25k
    return (channel->state > UA_SECURECHANNELSTATE_CLOSED &&
121
7.25k
            channel->state < UA_SECURECHANNELSTATE_CLOSING);
122
7.25k
}
123
124
void
125
831
UA_SecureChannel_sendERR(UA_SecureChannel *channel, UA_TcpErrorMessage *error) {
126
831
    if(!UA_SecureChannel_isConnected(channel))
127
139
        return;
128
129
692
    hideErrors(error);
130
131
692
    UA_TcpMessageHeader header;
132
692
    header.messageTypeAndChunkType = UA_MESSAGETYPE_ERR + UA_CHUNKTYPE_FINAL;
133
    /* Header + ErrorMessage (error + reasonLength_field + length) */
134
692
    header.messageSize = 8 + (4 + 4 + (UA_UInt32)error->reason.length);
135
136
    /* Get the send buffer from the network layer */
137
692
    UA_ConnectionManager *cm = channel->connectionManager;
138
692
    UA_ByteString msg = UA_BYTESTRING_NULL;
139
692
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, channel->connectionId,
140
692
                                                  &msg, header.messageSize);
141
692
    if(retval != UA_STATUSCODE_GOOD)
142
0
        return;
143
144
    /* Encode and send the response */
145
692
    UA_Byte *bufPos = msg.data;
146
692
    const UA_Byte *bufEnd = &msg.data[msg.length];
147
692
    retval |= UA_encodeBinaryInternal(&header,
148
692
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
149
692
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
150
692
    retval |= UA_encodeBinaryInternal(error,
151
692
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE],
152
692
                                      &bufPos, &bufEnd, NULL, NULL, NULL);
153
692
    (void)retval; /* Encoding of these cannot fail */
154
692
    msg.length = header.messageSize;
155
692
    cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &msg);
156
692
}
157
158
static void
159
22
UA_Chunk_delete(UA_Chunk *chunk) {
160
22
    if(chunk->copied)
161
21
        UA_ByteString_clear(&chunk->bytes);
162
22
    UA_free(chunk);
163
22
}
164
165
static void
166
13.1k
deleteChunks(UA_SecureChannel *channel) {
167
13.1k
    UA_Chunk *chunk, *chunk_tmp;
168
13.1k
    TAILQ_FOREACH_SAFE(chunk, &channel->chunks, pointers, chunk_tmp) {
169
21
        TAILQ_REMOVE(&channel->chunks, chunk, pointers);
170
21
        UA_Chunk_delete(chunk);
171
21
    }
172
13.1k
    channel->chunksCount = 0;
173
13.1k
    channel->chunksLength = 0;
174
13.1k
}
175
176
void
177
13.1k
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel) {
178
13.1k
    deleteChunks(channel);
179
13.1k
    if(channel->unprocessedCopied)
180
1.81k
        UA_ByteString_clear(&channel->unprocessed);
181
13.1k
}
182
183
void
184
UA_SecureChannel_shutdown(UA_SecureChannel *channel,
185
857
                          UA_ShutdownReason shutdownReason) {
186
    /* No open socket or already closing -> nothing to do */
187
857
    if(!UA_SecureChannel_isConnected(channel))
188
139
        return;
189
190
    /* Set the shutdown event for diagnostics */
191
718
    channel->shutdownReason= shutdownReason;
192
193
    /* Trigger the async closing of the connection */
194
718
    UA_ConnectionManager *cm = channel->connectionManager;
195
718
    cm->closeConnection(cm, channel->connectionId);
196
718
    channel->state = UA_SECURECHANNELSTATE_CLOSING;
197
718
}
198
199
void
200
6.35k
UA_SecureChannel_clear(UA_SecureChannel *channel) {
201
    /* No sessions must be attached to this any longer */
202
6.35k
    UA_assert(channel->sessions == NULL);
203
204
    /* Delete the channel context for the security policy */
205
6.35k
    UA_SecurityPolicy *sp = channel->securityPolicy;
206
6.35k
    if(sp) {
207
3.26k
        sp->deleteChannelContext(sp, channel->channelContext);
208
3.26k
        channel->securityPolicy = NULL;
209
3.26k
        channel->channelContext = NULL;
210
3.26k
        channel->enhancedSecurity = false;     /* No policy => not enhanced */
211
3.26k
        channel->legacySequenceNumbers = true; /* No policy => legacy */
212
3.26k
    }
213
214
    /* Remove remaining delayed callback */
215
6.35k
    if(channel->connectionManager &&
216
4.22k
       channel->connectionManager->eventSource.eventLoop) {
217
116
        UA_EventLoop *el = channel->connectionManager->eventSource.eventLoop;
218
116
        el->removeDelayedCallback(el, &channel->unprocessedDelayed);
219
116
    }
220
221
    /* The EventLoop connection is no longer valid */
222
6.35k
    channel->connectionId = 0;
223
6.35k
    channel->connectionManager = NULL;
224
225
    /* Clean up the SecurityToken */
226
6.35k
    UA_ChannelSecurityToken_clear(&channel->securityToken);
227
6.35k
    UA_ChannelSecurityToken_clear(&channel->altSecurityToken);
228
229
    /* Clean up certificate and nonces */
230
6.35k
    UA_ByteString_clear(&channel->remoteCertificate);
231
6.35k
    UA_ByteString_clear(&channel->localNonce);
232
6.35k
    UA_ByteString_clear(&channel->remoteNonce);
233
234
    /* Clean up the v1.05.07 SecureChannel elements */
235
6.35k
    UA_ByteString_clear(&channel->firstRequestSignature);
236
6.35k
    UA_ByteString_clear(&channel->currentIKM);
237
6.35k
    UA_ByteString_clear(&channel->channelThumbprint);
238
239
    /* Clean up endpointUrl and remoteAddress */
240
6.35k
    UA_String_clear(&channel->endpointUrl);
241
6.35k
    UA_String_clear(&channel->remoteAddress);
242
243
    /* Delete remaining chunks */
244
6.35k
    UA_SecureChannel_deleteBuffered(channel);
245
246
    /* Clean up namespace mapping */
247
6.35k
    UA_NamespaceMapping_delete(channel->namespaceMapping);
248
6.35k
    channel->namespaceMapping = NULL;
249
250
    /* Reset the SecureChannel for reuse (in the client) */
251
6.35k
    channel->securityMode = UA_MESSAGESECURITYMODE_INVALID;
252
6.35k
    channel->shutdownReason = UA_SHUTDOWNREASON_CLOSE;
253
6.35k
    memset(&channel->config, 0, sizeof(UA_ConnectionConfig));
254
6.35k
    channel->receiveSequenceNumber = 0;
255
6.35k
    channel->sendSequenceNumber = 0;
256
257
    /* Set the state to closed */
258
6.35k
    channel->state = UA_SECURECHANNELSTATE_CLOSED;
259
6.35k
    channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
260
6.35k
}
261
262
UA_StatusCode
263
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
264
1.14k
                               const UA_TcpAcknowledgeMessage *remoteConfig) {
265
    /* The lowest common version is used by both sides */
266
1.14k
    if(channel->config.protocolVersion > remoteConfig->protocolVersion)
267
0
        channel->config.protocolVersion = remoteConfig->protocolVersion;
268
269
    /* Can we receive the max send size? */
270
1.14k
    if(channel->config.sendBufferSize > remoteConfig->receiveBufferSize)
271
98
        channel->config.sendBufferSize = remoteConfig->receiveBufferSize;
272
273
    /* Can we send the max receive size? */
274
1.14k
    if(channel->config.recvBufferSize > remoteConfig->sendBufferSize)
275
94
        channel->config.recvBufferSize = remoteConfig->sendBufferSize;
276
277
1.14k
    channel->config.remoteMaxMessageSize = remoteConfig->maxMessageSize;
278
1.14k
    channel->config.remoteMaxChunkCount = remoteConfig->maxChunkCount;
279
280
    /* Chunks of at least 8192 bytes must be permissible.
281
     * See Part 6, Clause 6.7.1 */
282
1.14k
    if(channel->config.recvBufferSize < 8192 ||
283
1.10k
       channel->config.sendBufferSize < 8192 ||
284
1.07k
       (channel->config.remoteMaxMessageSize != 0 &&
285
1.04k
        channel->config.remoteMaxMessageSize < 8192))
286
101
        return UA_STATUSCODE_BADINTERNALERROR;
287
288
1.04k
    return UA_STATUSCODE_GOOD;
289
1.14k
}
290
291
/* Send an OPN message using asymmetric encryption.
292
 * Specification part 6, 6.7.4: The OpenSecureChannel Messages are signed and
293
 * encrypted if the SecurityMode is not None (even if the SecurityMode is
294
 * SignOnly). */
295
UA_StatusCode
296
UA_SecureChannel_sendOPN(UA_SecureChannel *channel,
297
                         UA_UInt32 requestId, const void *content,
298
440
                         const UA_DataType *contentType) {
299
440
    if(!content || !contentType)
300
0
        return UA_STATUSCODE_BADINTERNALERROR;
301
302
    /* The SecurityPolicy must be configured before sending OPN */
303
440
    const UA_SecurityPolicy *sp = channel->securityPolicy;
304
440
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
305
306
    /* Check for a valid security mode */
307
440
    UA_assert(channel->securityMode > UA_MESSAGESECURITYMODE_INVALID &&
308
440
              channel->securityMode <= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);
309
310
    /* The #None SecurityPolicy must use the NONE MessageSecurityMode.
311
     * All other SecurityPolicies must not. */
312
440
    UA_assert((sp->policyType == UA_SECURITYPOLICYTYPE_NONE) ==
313
440
              (channel->securityMode == UA_MESSAGESECURITYMODE_NONE));
314
315
    /* Can we use the connection manager? */
316
440
    UA_ConnectionManager *cm = channel->connectionManager;
317
440
    if(!UA_SecureChannel_isConnected(channel))
318
0
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
319
320
    /* Allocate the message buffer */
321
440
    UA_ByteString buf = UA_BYTESTRING_NULL;
322
440
    UA_StatusCode res = cm->allocNetworkBuffer(cm, channel->connectionId, &buf,
323
440
                                               channel->config.sendBufferSize);
324
440
    UA_CHECK_STATUS(res, return res);
325
326
    /* Restrict buffer to the available space for the payload */
327
440
    UA_Byte *buf_pos = buf.data;
328
440
    const UA_Byte *buf_end = &buf.data[buf.length];
329
440
    res = hideBytesAsym(channel, &buf_pos, &buf_end);
330
440
    UA_CHECK_STATUS(res, cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
331
440
                    return res);
332
333
    /* Define variables here to pacify some compilers wrt goto */
334
440
    size_t securityHeaderLength, pre_sig_length, total_length, encryptedLength;
335
336
    /* Encode the message type and content */
337
440
    UA_EncodeBinaryOptions encOpts;
338
440
    memset(&encOpts, 0, sizeof(UA_EncodeBinaryOptions));
339
440
    encOpts.namespaceMapping = channel->namespaceMapping;
340
440
    res |= UA_NodeId_encodeBinary(&contentType->binaryEncodingId, &buf_pos, buf_end);
341
440
    res |= UA_encodeBinaryInternal(content, contentType, &buf_pos, &buf_end,
342
440
                                   &encOpts, NULL, NULL);
343
440
    UA_CHECK_STATUS(res, goto error);
344
345
    /* Compute the header length */
346
440
    securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel);
347
348
    /* Add padding to the chunk */
349
440
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE)
350
0
        padChunk(channel, &sp->asymSignatureAlgorithm, &sp->asymEncryptionAlgorithm,
351
0
                 &buf.data[UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength],
352
0
                 &buf_pos);
353
354
    /* The total message length */
355
440
    pre_sig_length = (uintptr_t)buf_pos - (uintptr_t)buf.data;
356
440
    total_length = pre_sig_length;
357
440
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE)
358
0
        total_length += sp->asymSignatureAlgorithm.
359
0
            getLocalSignatureSize(sp, channel->channelContext);
360
361
    /* The total message length is known here which is why we encode the headers
362
     * at this step and not earlier. */
363
440
    res = prependHeadersAsym(channel, buf.data, buf_end, total_length,
364
440
                             securityHeaderLength, requestId, &encryptedLength);
365
440
    UA_CHECK_STATUS(res, goto error);
366
367
    /* Add the signature and encrypt the message */
368
440
    res = signAndEncryptAsym(channel, pre_sig_length, &buf,
369
440
                             securityHeaderLength, total_length);
370
440
    UA_CHECK_STATUS(res, goto error);
371
372
    /* Send the message, the buffer is freed in the network layer */
373
440
    buf.length = encryptedLength;
374
440
    return cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &buf);
375
376
0
 error:
377
0
    cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
378
0
    return res;
379
440
}
380
381
/* Will this chunk surpass the capacity of the SecureChannel for the message? */
382
static UA_StatusCode
383
897
adjustCheckMessageLimitsSym(UA_MessageContext *mc, size_t bodyLength) {
384
897
    mc->messageSizeSoFar += bodyLength;
385
897
    mc->chunksSoFar++;
386
387
897
    UA_SecureChannel *channel = mc->channel;
388
897
    if(mc->messageSizeSoFar > channel->config.localMaxMessageSize &&
389
0
       channel->config.localMaxMessageSize != 0)
390
0
        return UA_STATUSCODE_BADRESPONSETOOLARGE;
391
392
897
    if(mc->chunksSoFar > channel->config.localMaxChunkCount &&
393
0
       channel->config.localMaxChunkCount != 0)
394
0
        return UA_STATUSCODE_BADRESPONSETOOLARGE;
395
396
897
    return UA_STATUSCODE_GOOD;
397
897
}
398
399
static UA_StatusCode
400
897
encodeHeadersSym(UA_MessageContext *mc, size_t totalLength) {
401
897
    UA_SecureChannel *channel = mc->channel;
402
897
    UA_Byte *header_pos = mc->messageBuffer.data;
403
404
897
    UA_TcpMessageHeader header;
405
897
    header.messageTypeAndChunkType = mc->messageType;
406
897
    header.messageSize = (UA_UInt32)totalLength;
407
897
    if(mc->final)
408
897
        header.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
409
0
    else
410
0
        header.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE;
411
412
897
    UA_SequenceHeader seqHeader;
413
897
    seqHeader.requestId = mc->requestId;
414
897
    seqHeader.sequenceNumber = UA_SecureChannel_nextSequenceNumber(channel);
415
416
897
    UA_StatusCode res = UA_STATUSCODE_GOOD;
417
897
    res |= UA_encodeBinaryInternal(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
418
897
                                   &header_pos, &mc->buf_end, NULL, NULL, NULL);
419
897
    res |= UA_UInt32_encodeBinary(&channel->securityToken.channelId,
420
897
                                  &header_pos, mc->buf_end);
421
897
    res |= UA_UInt32_encodeBinary(&channel->securityToken.tokenId,
422
897
                                  &header_pos, mc->buf_end);
423
897
    res |= UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
424
897
                                   &header_pos, &mc->buf_end, NULL, NULL, NULL);
425
897
    return res;
426
897
}
427
428
static UA_StatusCode
429
897
sendSymmetricChunk(UA_MessageContext *mc) {
430
897
    UA_SecureChannel *channel = mc->channel;
431
897
    const UA_SecurityPolicy *sp = channel->securityPolicy;
432
897
    UA_ConnectionManager *cm = channel->connectionManager;
433
897
    if(!UA_SecureChannel_isConnected(channel))
434
0
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
435
436
    /* The size of the message payload */
437
897
    size_t bodyLength = (uintptr_t)mc->buf_pos -
438
897
        (uintptr_t)&mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH];
439
440
    /* Early-declare variables so we can use a goto in the error case */
441
897
    size_t total_length = 0;
442
897
    size_t pre_sig_length = 0;
443
444
    /* Check if chunk exceeds the limits for the overall message */
445
897
    UA_StatusCode res = adjustCheckMessageLimitsSym(mc, bodyLength);
446
897
    UA_CHECK_STATUS(res, goto error);
447
448
897
    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
449
897
                         "Send from a symmetric message buffer of length %lu "
450
897
                         "a message of header+payload length of %lu",
451
897
                         (long unsigned int)mc->messageBuffer.length,
452
897
                         (long unsigned int)
453
897
                         ((uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data));
454
455
    /* Add padding if the message is encrypted (not for AEAD policies) */
456
897
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
457
0
       !UA_SecurityPolicy_isAead(sp))
458
0
        padChunk(channel, &sp->symSignatureAlgorithm, &sp->symEncryptionAlgorithm,
459
0
                 &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH],
460
0
                 &mc->buf_pos);
461
462
    /* Compute the total message length */
463
897
    pre_sig_length = (uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data;
464
897
    total_length = pre_sig_length;
465
897
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
466
897
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
467
0
        total_length += sp->symSignatureAlgorithm.
468
0
            getLocalSignatureSize(sp, channel->channelContext);
469
470
897
    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
471
897
                         "Send from a symmetric message buffer of length %lu "
472
897
                         "a message of length %lu",
473
897
                         (long unsigned int)mc->messageBuffer.length,
474
897
                         (long unsigned int)total_length);
475
476
    /* Space for the padding and the signature have been reserved in setBufPos() */
477
897
    UA_assert(total_length <= channel->config.sendBufferSize);
478
479
    /* Adjust the buffer size of the network layer */
480
897
    mc->messageBuffer.length = total_length;
481
482
    /* Generate and encode the header for symmetric messages */
483
897
    res = encodeHeadersSym(mc, total_length);
484
897
    UA_CHECK_STATUS(res, goto error);
485
486
    /* Sign and encrypt the messge */
487
897
    res = signAndEncryptSym(mc, pre_sig_length, total_length);
488
897
    UA_CHECK_STATUS(res, goto error);
489
490
    /* Send the chunk. The buffer is freed in the network layer. If sending goes
491
     * wrong, the connection is removed in the next iteration of the
492
     * SecureChannel. Set the SecureChannel to closing already. */
493
897
    res = cm->sendWithConnection(cm, channel->connectionId,
494
897
                                 &UA_KEYVALUEMAP_NULL, &mc->messageBuffer);
495
897
    if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
496
0
        channel->state = UA_SECURECHANNELSTATE_CLOSING;
497
897
    return res;
498
499
0
 error:
500
    /* Free the unused message buffer */
501
0
    cm->freeNetworkBuffer(cm, channel->connectionId, &mc->messageBuffer);
502
0
    return res;
503
897
}
504
505
/* Callback from the encoding layer. Send the chunk and replace the buffer. */
506
static UA_StatusCode
507
sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos,
508
0
                              const UA_Byte **buf_end) {
509
    /* Set buf values from encoding in the messagecontext */
510
0
    UA_MessageContext *mc = (UA_MessageContext *)data;
511
0
    mc->buf_pos = *buf_pos;
512
0
    mc->buf_end = *buf_end;
513
514
    /* Send out */
515
0
    UA_StatusCode res = sendSymmetricChunk(mc);
516
0
    UA_CHECK_STATUS(res, return res);
517
518
    /* Set a new buffer for the next chunk */
519
0
    UA_ConnectionManager *cm = mc->channel->connectionManager;
520
0
    if(!UA_SecureChannel_isConnected(mc->channel))
521
0
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
522
523
0
    res = cm->allocNetworkBuffer(cm, mc->channel->connectionId,
524
0
                                 &mc->messageBuffer,
525
0
                                 mc->channel->config.sendBufferSize);
526
0
    UA_CHECK_STATUS(res, return res);
527
528
    /* Hide bytes for header, padding and signature */
529
0
    setBufPos(mc);
530
0
    *buf_pos = mc->buf_pos;
531
0
    *buf_end = mc->buf_end;
532
0
    return UA_STATUSCODE_GOOD;
533
0
}
534
535
UA_StatusCode
536
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
537
897
                        UA_UInt32 requestId, UA_MessageType messageType) {
538
897
    UA_CHECK(messageType == UA_MESSAGETYPE_MSG || messageType == UA_MESSAGETYPE_CLO,
539
897
             return UA_STATUSCODE_BADINTERNALERROR);
540
541
897
    UA_ConnectionManager *cm = channel->connectionManager;
542
897
    if(!UA_SecureChannel_isConnected(channel))
543
0
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
544
545
    /* Create the chunking info structure */
546
897
    mc->channel = channel;
547
897
    mc->requestId = requestId;
548
897
    mc->chunksSoFar = 0;
549
897
    mc->messageSizeSoFar = 0;
550
897
    mc->final = false;
551
897
    mc->messageBuffer = UA_BYTESTRING_NULL;
552
897
    mc->messageType = messageType;
553
554
    /* Allocate the message buffer */
555
897
    UA_StatusCode res =
556
897
        cm->allocNetworkBuffer(cm, channel->connectionId,
557
897
                               &mc->messageBuffer,
558
897
                               channel->config.sendBufferSize);
559
897
    UA_CHECK_STATUS(res, return res);
560
561
    /* Hide bytes for header, padding and signature */
562
897
    setBufPos(mc);
563
897
    return UA_STATUSCODE_GOOD;
564
897
}
565
566
UA_StatusCode
567
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
568
1.79k
                         const UA_DataType *contentType) {
569
1.79k
    UA_EncodeBinaryOptions encOpts;
570
1.79k
    memset(&encOpts, 0, sizeof(UA_EncodeBinaryOptions));
571
1.79k
    encOpts.namespaceMapping = mc->channel->namespaceMapping;
572
1.79k
    UA_StatusCode res =
573
1.79k
        UA_encodeBinaryInternal(content, contentType, &mc->buf_pos, &mc->buf_end,
574
1.79k
                                &encOpts, sendSymmetricEncodingCallback, mc);
575
1.79k
    if(res != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0)
576
0
        UA_MessageContext_abort(mc);
577
1.79k
    return res;
578
1.79k
}
579
580
UA_StatusCode
581
897
UA_MessageContext_finish(UA_MessageContext *mc) {
582
897
    mc->final = true;
583
897
    return sendSymmetricChunk(mc);
584
897
}
585
586
void
587
0
UA_MessageContext_abort(UA_MessageContext *mc) {
588
0
    UA_ConnectionManager *cm = mc->channel->connectionManager;
589
0
    if(!UA_SecureChannel_isConnected(mc->channel))
590
0
        return;
591
0
    cm->freeNetworkBuffer(cm, mc->channel->connectionId, &mc->messageBuffer);
592
0
}
593
594
/* Send a MSG or CLO message using symmetric encryption */
595
static UA_StatusCode
596
sendSymmetric(UA_SecureChannel *channel, UA_UInt32 requestId,
597
              UA_MessageType messageType, void *payload,
598
897
              const UA_DataType *payloadType) {
599
897
    if(!channel || !payload || !payloadType)
600
0
        return UA_STATUSCODE_BADINTERNALERROR;
601
602
897
    if(channel->state != UA_SECURECHANNELSTATE_OPEN)
603
0
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
604
605
897
    UA_MessageContext mc;
606
897
    UA_StatusCode res = UA_MessageContext_begin(&mc, channel, requestId, messageType);
607
897
    UA_CHECK_STATUS(res, return res);
608
609
    /* Assert's required for clang-analyzer */
610
897
    UA_assert(mc.buf_pos ==
611
897
              &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]);
612
897
    UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]);
613
614
897
    res = UA_MessageContext_encode(&mc, &payloadType->binaryEncodingId,
615
897
                                   &UA_TYPES[UA_TYPES_NODEID]);
616
897
    UA_CHECK_STATUS(res, return res);
617
618
897
    res = UA_MessageContext_encode(&mc, payload, payloadType);
619
897
    UA_CHECK_STATUS(res, return res);
620
621
897
    return UA_MessageContext_finish(&mc);
622
897
}
623
624
UA_StatusCode
625
UA_SecureChannel_sendMSG(UA_SecureChannel *channel, UA_UInt32 requestId,
626
                         void *payload, const UA_DataType *payloadType) {
627
    return sendSymmetric(channel, requestId, UA_MESSAGETYPE_MSG,
628
                         payload, payloadType);
629
}
630
631
UA_StatusCode
632
UA_SecureChannel_sendCLO(UA_SecureChannel *channel, UA_UInt32 requestId,
633
0
                         UA_CloseSecureChannelRequest *req) {
634
0
    return sendSymmetric(channel, requestId, UA_MESSAGETYPE_CLO, req,
635
0
                         &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
636
0
}
637
638
/********************************/
639
/* Receive and Process Messages */
640
/********************************/
641
642
/* Does the sequence number match? Otherwise try to rollover. See Part 6,
643
 * Section 6.7.2.4 of the standard. */
644
1.33k
#define UA_SEQUENCENUMBER_ROLLOVER 4294966271
645
646
UA_UInt32
647
1.33k
UA_SecureChannel_nextSequenceNumber(UA_SecureChannel *channel) {
648
    /* channel->sendSequenceNumber mirrors the reference-stack counter: a
649
     * pre-increment value initialized to 0. The legacy scheme emits the
650
     * counter (first = 1); the non-legacy scheme emits counter-1 (first = 0). */
651
1.33k
    UA_UInt64 next = (UA_UInt64)channel->sendSequenceNumber + 1;
652
1.33k
    if(channel->legacySequenceNumbers) {
653
        /* Legacy rollover: the first number after the max is 1. */
654
1.33k
        if(next > UA_SEQUENCENUMBER_ROLLOVER)
655
0
            next = 1;
656
1.33k
        channel->sendSequenceNumber = (UA_UInt32)next;
657
1.33k
        return channel->sendSequenceNumber;
658
1.33k
    }
659
    /* Non-legacy: the counter wraps to 0 after UA_UINT32_MAX so the emitted
660
     * value (counter - 1) covers the full UInt32 range and then restarts at 0. */
661
0
    if(next > UA_UINT32_MAX)
662
0
        next = 0;
663
0
    channel->sendSequenceNumber = (UA_UInt32)next;
664
0
    return (channel->sendSequenceNumber == 0) ?
665
0
        UA_UINT32_MAX : (channel->sendSequenceNumber - 1);
666
1.33k
}
667
668
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
669
static UA_StatusCode
670
processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
671
    if(sequenceNumber != channel->receiveSequenceNumber + 1) {
672
        /* The non-legacy (ECC) rollover from UA_UINT32_MAX to 0 is already
673
         * accepted by the check above (unsigned overflow makes
674
         * receiveSequenceNumber + 1 == 0). Only the legacy "< 1024" rollover
675
         * needs the special case below; non-legacy policies reject anything
676
         * that is not the immediate successor. */
677
        if(!channel->legacySequenceNumbers ||
678
           channel->receiveSequenceNumber + 1 <= UA_SEQUENCENUMBER_ROLLOVER ||
679
           sequenceNumber >= 1024)
680
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
681
        channel->receiveSequenceNumber = sequenceNumber - 1; /* Roll over */
682
    }
683
    ++channel->receiveSequenceNumber;
684
    return UA_STATUSCODE_GOOD;
685
}
686
#endif
687
688
static UA_StatusCode
689
742
unpackPayloadOPN(UA_SecureChannel *channel, UA_Chunk *chunk) {
690
742
    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
691
742
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
692
742
    UA_UInt32 secureChannelId;
693
742
    UA_StatusCode res = UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
694
742
    UA_assert(res == UA_STATUSCODE_GOOD);
695
696
742
    UA_AsymmetricAlgorithmSecurityHeader asymHeader;
697
742
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &asymHeader,
698
742
             &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL);
699
742
    UA_CHECK_STATUS(res, return res);
700
701
    /* Declare before the first goto to avoid crosses-initialization in C++ */
702
717
    UA_SecurityPolicy *sp = NULL;
703
704
    /* Client/Server-specific processing. Creates a SecurityPolicy context and
705
     * attaches it to the channel. For the client, the remote certificate has
706
     * been verified before connecting. For the server the remote certificate is
707
     * verified within processOPNHeader. */
708
717
    UA_assert(channel->processOPNHeader);
709
717
    res = channel->processOPNHeader(channel->processOPNHeaderApplication,
710
717
                                    channel, &asymHeader);
711
717
    UA_CHECK_STATUS(res, goto error);
712
713
    /* On the client side, take the SecureChannelId from the first response */
714
583
    if(secureChannelId != 0 && channel->securityToken.channelId == 0)
715
0
        channel->securityToken.channelId = secureChannelId;
716
717
    /* Check the ChannelId */
718
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
719
    if(secureChannelId != channel->securityToken.channelId) {
720
        /* Allow the channel id to be different if the sent channel id is zero
721
         * and the SecurityToken is not initialized. This only happens on the
722
         * server side before we had a chance to tell the client which ChannelId
723
         * to use. */
724
        if(secureChannelId != 0 || channel->securityToken.tokenId != 0) {
725
            res = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
726
            goto error;
727
        }
728
    }
729
#endif
730
731
    /* Generic header checking (for both client and server). Requires the
732
     * channel's SecurityPolicy. */
733
583
    res = checkAsymHeader(channel, &asymHeader);
734
583
    UA_CHECK_STATUS(res, goto error);
735
736
581
    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);
737
738
    /* Decrypt the chunk payload */
739
581
    sp = channel->securityPolicy;
740
581
    res = decryptAndVerifyChunk(channel, &sp->asymSignatureAlgorithm,
741
581
                                &sp->asymEncryptionAlgorithm,
742
581
                                chunk->messageType, &chunk->bytes, offset);
743
581
    UA_CHECK_STATUS(res, return res);
744
745
    /* Decode the SequenceHeader */
746
579
    UA_SequenceHeader sequenceHeader;
747
579
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
748
579
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
749
579
    UA_CHECK_STATUS(res, return res);
750
751
    /* Only the initial OPN establishes the receive sequence. Renewals remain
752
     * part of the existing channel's monotonically increasing sequence. */
753
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
754
    if(channel->state == UA_SECURECHANNELSTATE_OPEN) {
755
        res = processSequenceNumberSym(channel, sequenceHeader.sequenceNumber);
756
        UA_CHECK_STATUS(res, return res);
757
    } else
758
#endif
759
579
    {
760
579
        channel->receiveSequenceNumber = sequenceHeader.sequenceNumber;
761
579
    }
762
579
    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */
763
764
    /* Use only the payload */
765
579
    chunk->bytes.data += offset;
766
579
    chunk->bytes.length -= offset;
767
579
    return UA_STATUSCODE_GOOD;
768
769
136
error:
770
136
    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);
771
136
    return res;
772
579
}
773
774
static UA_StatusCode
775
unpackPayloadMSG(UA_SecureChannel *channel, UA_Chunk *chunk,
776
1.11k
                 UA_DateTime nowMonotonic) {
777
1.11k
    UA_CHECK_MEM(channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR);
778
779
1.11k
    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
780
1.11k
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
781
1.11k
    UA_UInt32 secureChannelId;
782
1.11k
    UA_UInt32 tokenId; /* SymmetricAlgorithmSecurityHeader */
783
1.11k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
784
1.11k
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
785
1.11k
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &tokenId);
786
1.11k
    UA_assert(offset == UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
787
1.11k
    UA_assert(res == UA_STATUSCODE_GOOD);
788
789
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
790
    /* Check the ChannelId. Non-opened channels have the id zero. */
791
    if(secureChannelId != channel->securityToken.channelId)
792
        return UA_STATUSCODE_BADSECURECHANNELIDINVALID;
793
#endif
794
795
    /* Check (and revolve) the SecurityToken */
796
1.11k
    res = checkSymHeader(channel, tokenId, nowMonotonic);
797
1.11k
    UA_CHECK_STATUS(res, return res);
798
799
    /* Decrypt the chunk payload */
800
1.02k
    UA_SecurityPolicy *sp = channel->securityPolicy;
801
1.02k
    res = decryptAndVerifyChunk(channel, &sp->symSignatureAlgorithm,
802
1.02k
                                &sp->symEncryptionAlgorithm,
803
1.02k
                                chunk->messageType, &chunk->bytes, offset);
804
1.02k
    UA_CHECK_STATUS(res, return res);
805
806
    /* Check the sequence number. Skip sequence number checking for fuzzer to
807
     * improve coverage */
808
1.02k
    UA_SequenceHeader sequenceHeader;
809
1.02k
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
810
1.02k
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
811
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
812
    res |= processSequenceNumberSym(channel, sequenceHeader.sequenceNumber);
813
#endif
814
1.02k
    UA_CHECK_STATUS(res, return res);
815
816
1.02k
    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */
817
818
    /* Use only the payload */
819
1.02k
    chunk->bytes.data += offset;
820
1.02k
    chunk->bytes.length -= offset;
821
1.02k
    return UA_STATUSCODE_GOOD;
822
1.02k
}
823
824
static UA_StatusCode
825
extractCompleteChunk(UA_SecureChannel *channel, UA_Chunk *chunk,
826
5.15k
                     UA_DateTime nowMonotonic) {
827
    /* At least 8 byte needed for the header */
828
5.15k
    size_t offset = channel->unprocessedOffset;
829
5.15k
    size_t remaining = channel->unprocessed.length - offset;
830
5.15k
    if(remaining < UA_SECURECHANNEL_MESSAGEHEADER_LENGTH)
831
720
        return UA_STATUSCODE_GOOD;
832
833
    /* Decoding the header cannot fail */
834
4.43k
    UA_TcpMessageHeader hdr;
835
4.43k
    UA_StatusCode res =
836
4.43k
        UA_decodeBinaryInternal(&channel->unprocessed, &offset, &hdr,
837
4.43k
                                &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL);
838
4.43k
    UA_assert(res == UA_STATUSCODE_GOOD);
839
4.43k
    (void)res; /* pacify compilers if assert is ignored */
840
4.43k
    UA_MessageType msgType = (UA_MessageType)
841
4.43k
        (hdr.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE);
842
4.43k
    UA_ChunkType chunkType = (UA_ChunkType)
843
4.43k
        (hdr.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE);
844
845
    /* The message size is not allowed */
846
4.43k
    if(hdr.messageSize < UA_SECURECHANNEL_MESSAGE_MIN_LENGTH)
847
61
        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
848
4.37k
    if(hdr.messageSize > channel->config.recvBufferSize)
849
456
        return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
850
851
    /* Incomplete chunk. Continue processing later. */
852
3.91k
    if(hdr.messageSize > remaining)
853
91
        return UA_STATUSCODE_GOOD;
854
855
    /* Set the chunk information */
856
3.82k
    chunk->bytes.data = channel->unprocessed.data + channel->unprocessedOffset;
857
3.82k
    chunk->bytes.length = hdr.messageSize;
858
3.82k
    chunk->messageType = msgType;
859
3.82k
    chunk->chunkType = chunkType;
860
3.82k
    chunk->requestId = 0;
861
3.82k
    chunk->copied = false;
862
863
    /* Increase the unprocessed offset */
864
3.82k
    channel->unprocessedOffset += hdr.messageSize;
865
866
    /* Validate, decrypt and unpack the chunk payload */
867
3.82k
    switch(msgType) {
868
759
    case UA_MESSAGETYPE_OPN:
869
759
        if(chunkType != UA_CHUNKTYPE_FINAL)
870
8
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
871
751
        if(channel->state != UA_SECURECHANNELSTATE_OPEN &&
872
746
           channel->state != UA_SECURECHANNELSTATE_OPN_SENT &&
873
746
           channel->state != UA_SECURECHANNELSTATE_ACK_SENT)
874
9
            return UA_STATUSCODE_BADINVALIDSTATE;
875
742
        res = unpackPayloadOPN(channel, chunk);
876
742
        break;
877
878
1.25k
    case UA_MESSAGETYPE_MSG:
879
1.30k
    case UA_MESSAGETYPE_CLO:
880
1.30k
        if(chunkType != UA_CHUNKTYPE_FINAL &&
881
58
           chunkType != UA_CHUNKTYPE_INTERMEDIATE &&
882
33
           chunkType != UA_CHUNKTYPE_ABORT)
883
27
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
884
1.27k
        if(channel->state != UA_SECURECHANNELSTATE_OPEN)
885
168
            return UA_STATUSCODE_BADINVALIDSTATE;
886
1.11k
        res = unpackPayloadMSG(channel, chunk, nowMonotonic);
887
1.11k
        break;
888
889
1
    case UA_MESSAGETYPE_RHE:
890
1.26k
    case UA_MESSAGETYPE_HEL:
891
1.26k
    case UA_MESSAGETYPE_ACK:
892
1.27k
    case UA_MESSAGETYPE_ERR:
893
1.27k
        if(chunkType != UA_CHUNKTYPE_FINAL)
894
17
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
895
        /* Hide the message header */
896
1.25k
        chunk->bytes.data += UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
897
1.25k
        chunk->bytes.length -= UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
898
1.25k
        break;
899
900
490
    default:
901
490
        res = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
902
490
        break;
903
3.82k
    }
904
3.59k
    return res;
905
3.82k
}
906
907
UA_StatusCode
908
2.69k
UA_SecureChannel_loadBuffer(UA_SecureChannel *channel, const UA_ByteString buffer) {
909
    /* Append to the previous unprocessed buffer */
910
2.69k
    if(channel->unprocessed.length > 0) {
911
0
        UA_assert(channel->unprocessedCopied == true);
912
913
0
        UA_Byte *t = (UA_Byte*)
914
0
            UA_realloc(channel->unprocessed.data,
915
0
                       channel->unprocessed.length + buffer.length);
916
0
        if(!t)
917
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
918
919
0
        if(buffer.length)
920
0
            memcpy(t + channel->unprocessed.length, buffer.data, buffer.length);
921
0
        channel->unprocessed.data = t;
922
0
        channel->unprocessed.length += buffer.length;
923
0
        return UA_STATUSCODE_GOOD;
924
0
    }
925
926
    /* Use the new buffer directly */
927
2.69k
    channel->unprocessed = buffer;
928
2.69k
    channel->unprocessedCopied = false;
929
2.69k
    return UA_STATUSCODE_GOOD;
930
2.69k
}
931
932
UA_StatusCode
933
UA_SecureChannel_getCompleteMessage(UA_SecureChannel *channel,
934
                                    UA_MessageType *messageType, UA_UInt32 *requestId,
935
                                    UA_ByteString *payload, UA_Boolean *copied,
936
5.13k
                                    UA_DateTime nowMonotonic) {
937
5.13k
    UA_Chunk chunk, *pchunk;
938
5.13k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
939
940
5.15k
 extract_chunk:
941
    /* Extract+decode the next chunk from the buffer */
942
5.15k
    memset(&chunk, 0, sizeof(UA_Chunk));
943
5.15k
    res = extractCompleteChunk(channel, &chunk, nowMonotonic);
944
5.15k
    if(chunk.bytes.length == 0 || res != UA_STATUSCODE_GOOD)
945
2.29k
        return res; /* Error or no complete chunk could be extracted */
946
947
    /* Process the chunk */
948
2.85k
    switch(chunk.chunkType) {
949
2
    case UA_CHUNKTYPE_ABORT:
950
        /* Remove all chunks received so far. Then continue extracting chunks. */
951
2
        deleteChunks(channel);
952
2
        if(chunk.copied)
953
0
            UA_ByteString_clear(&chunk.bytes);
954
2
        goto extract_chunk;
955
956
22
    case UA_CHUNKTYPE_INTERMEDIATE:
957
        /* Validate the resource limits */
958
22
        if((channel->config.localMaxChunkCount != 0 &&
959
22
            channel->chunksCount >= channel->config.localMaxChunkCount) ||
960
22
           (channel->config.localMaxMessageSize != 0 &&
961
22
            channel->chunksLength + chunk.bytes.length > channel->config.localMaxMessageSize)) {
962
0
            if(chunk.copied)
963
0
                UA_ByteString_clear(&chunk.bytes);
964
0
            return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
965
0
        }
966
967
        /* Add the chunk to the queue. Then continue extracting more chunks. */
968
22
        pchunk = (UA_Chunk*)UA_malloc(sizeof(UA_Chunk));
969
22
        if(!pchunk) {
970
0
            if(chunk.copied)
971
0
                UA_ByteString_clear(&chunk.bytes);
972
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
973
0
        }
974
22
        *pchunk = chunk;
975
22
        TAILQ_INSERT_TAIL(&channel->chunks, pchunk, pointers);
976
22
        channel->chunksCount++;
977
22
        channel->chunksLength += pchunk->bytes.length;
978
22
        goto extract_chunk;
979
980
2.83k
    case UA_CHUNKTYPE_FINAL:
981
2.83k
    default:
982
2.83k
        UA_assert(chunk.chunkType == UA_CHUNKTYPE_FINAL); /* Was checked before */
983
2.83k
        break; /* A final chunk was received -- assemble the message */
984
2.85k
    }
985
986
    /* Compute the message size */
987
2.83k
    size_t messageSize = chunk.bytes.length;
988
2.83k
    size_t messageChunks = 1; /* Include the final chunk */
989
2.83k
    UA_Chunk *first = NULL;
990
2.83k
    TAILQ_FOREACH(pchunk, &channel->chunks, pointers) {
991
49
        if(chunk.requestId != pchunk->requestId)
992
48
            continue;
993
1
        if(chunk.messageType != pchunk->messageType) {
994
0
            if(chunk.copied)
995
0
                UA_ByteString_clear(&chunk.bytes);
996
0
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
997
0
        }
998
1
        if(!first)
999
1
            first = pchunk;
1000
1
        messageChunks++;
1001
1
        messageSize += pchunk->bytes.length;
1002
1
    }
1003
1004
    /* Validate the assembled message limits. The final chunk also counts
1005
     * towards localMaxChunkCount. */
1006
2.83k
    if((channel->config.localMaxChunkCount != 0 &&
1007
2.83k
        messageChunks > channel->config.localMaxChunkCount) ||
1008
2.83k
       (channel->config.localMaxMessageSize != 0 &&
1009
2.83k
        messageSize > channel->config.localMaxMessageSize)) {
1010
0
        if(chunk.copied)
1011
0
            UA_ByteString_clear(&chunk.bytes);
1012
0
        return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
1013
0
    }
1014
1015
    /* Assemble the full payload and store it in chunk.bytes */
1016
2.83k
    if(messageSize > chunk.bytes.length) {
1017
1
        UA_assert(first != NULL);
1018
1019
        /* Allocate the full memory and initialize with the first chunk content.
1020
         * Use realloc to speed up. */
1021
1
        UA_ByteString message;
1022
1
        if(first->copied) {
1023
0
            message.data = (UA_Byte*)UA_realloc(first->bytes.data, messageSize);
1024
1
        } else {
1025
1
            message.data = (UA_Byte*)UA_malloc(messageSize);
1026
1
            if(message.data)
1027
1
                memcpy(message.data, first->bytes.data, first->bytes.length);
1028
1
        }
1029
1
        if(!message.data) {
1030
0
            if(chunk.copied)
1031
0
                UA_ByteString_clear(&chunk.bytes);
1032
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
1033
0
        }
1034
1
        message.length = first->bytes.length;
1035
1036
        /* Remove the the first chunk */
1037
1
        pchunk = TAILQ_NEXT(first, pointers);
1038
1
        first->copied = false;
1039
1
        channel->chunksCount--;
1040
1
        channel->chunksLength -= first->bytes.length;
1041
1
        TAILQ_REMOVE(&channel->chunks, first, pointers);
1042
1
        UA_Chunk_delete(first);
1043
1044
        /* Copy over the content from the remaining intermediate chunks.
1045
         * And remove them right away. */
1046
1
        UA_Chunk *next;
1047
1
        for(; pchunk; pchunk = next) {
1048
0
            next = TAILQ_NEXT(pchunk, pointers);
1049
0
            if(chunk.requestId != pchunk->requestId)
1050
0
                continue;
1051
0
            memcpy(message.data + message.length, pchunk->bytes.data, pchunk->bytes.length);
1052
0
            message.length += pchunk->bytes.length;
1053
0
            channel->chunksCount--;
1054
0
            channel->chunksLength -= pchunk->bytes.length;
1055
0
            TAILQ_REMOVE(&channel->chunks, pchunk, pointers);
1056
0
            UA_Chunk_delete(pchunk);
1057
0
        }
1058
1059
        /* Copy over the content from the final chunk */
1060
1
        memcpy(message.data + message.length, chunk.bytes.data, chunk.bytes.length);
1061
1
        message.length += chunk.bytes.length;
1062
1
        UA_assert(message.length == messageSize);
1063
1064
        /* Set assembled message as the content of the final chunk */
1065
1
        if(chunk.copied)
1066
0
            UA_ByteString_clear(&chunk.bytes);
1067
1
        chunk.bytes = message;
1068
1
        chunk.copied = true;
1069
1
    }
1070
1071
    /* Return the assembled message */
1072
2.83k
    *requestId = chunk.requestId;
1073
2.83k
    *messageType = chunk.messageType;
1074
2.83k
    *payload = chunk.bytes;
1075
2.83k
    *copied = chunk.copied;
1076
2.83k
    return UA_STATUSCODE_GOOD;
1077
2.83k
}
1078
1079
UA_StatusCode
1080
2.69k
UA_SecureChannel_persistBuffer(UA_SecureChannel *channel) {
1081
2.69k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1082
1083
    /* Persist the chunks */
1084
2.69k
    UA_Chunk *chunk;
1085
2.69k
    TAILQ_FOREACH(chunk, &channel->chunks, pointers) {
1086
21
        if(chunk->copied)
1087
0
            continue;
1088
21
        UA_ByteString tmp = UA_BYTESTRING_NULL;
1089
21
        res |= UA_ByteString_copy(&chunk->bytes, &tmp);
1090
21
        chunk->bytes = tmp;
1091
21
        chunk->copied = true;
1092
21
    }
1093
1094
    /* No unprocessed bytes remaining */
1095
2.69k
    UA_assert(channel->unprocessed.length >= channel->unprocessedOffset);
1096
2.69k
    if(channel->unprocessed.length == channel->unprocessedOffset) {
1097
875
        if(channel->unprocessedCopied)
1098
0
            UA_ByteString_clear(&channel->unprocessed);
1099
875
        else
1100
875
            UA_ByteString_init(&channel->unprocessed);
1101
875
        channel->unprocessedOffset = 0;
1102
875
        return res;
1103
875
    }
1104
1105
    /* Allocate a new unprocessed ByteString.
1106
     * tmp is the empty string if malloc fails. */
1107
1.81k
    UA_ByteString tmp = UA_BYTESTRING_NULL;
1108
1.81k
    UA_ByteString remaining = channel->unprocessed;
1109
1.81k
    remaining.data += channel->unprocessedOffset;
1110
1.81k
    remaining.length -= channel->unprocessedOffset;
1111
1.81k
    res |= UA_ByteString_copy(&remaining, &tmp);
1112
1.81k
    if(channel->unprocessedCopied)
1113
0
        UA_ByteString_clear(&channel->unprocessed);
1114
1.81k
    channel->unprocessed = tmp;
1115
1.81k
    channel->unprocessedOffset = 0;
1116
    channel->unprocessedCopied = true;
1117
1.81k
    return res;
1118
2.69k
}