open62541 1.3.12
Open source implementation of OPC UA
Loading...
Searching...
No Matches
ua_securechannel.h
Go to the documentation of this file.
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#include <open62541/util.h>
15#include <open62541/types.h>
19
20#include "open62541_queue.h"
22
24
25/** The message header of the OPC UA binary protocol is structured as follows:
26 *
27 * - MessageType (3 Byte)
28 * - IsFinal (1 Byte)
29 * - MessageSize (4 Byte)
30 * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH ***
31 * - SecureChannelId (4 Byte)
32 * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH ***
33 * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length)
34 * - SequenceHeader (8 Byte)
35 * - SequenceNumber
36 * - RequestId
37 */
38
39#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8
40#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12
41#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4
42#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8
43#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \
44 (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \
45 UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH)
46#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH \
47 (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \
48 UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH + \
49 UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH)
50
51/** Minimum length of a valid message (ERR message with an empty reason) */
52#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16
53
54/** Thread-local variables to force failure modes during testing */
55#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
56extern UA_StatusCode decrypt_verifySignatureFailure;
57extern UA_StatusCode sendAsym_sendFailure;
58extern UA_StatusCode processSym_seqNumberFailure;
59#endif
60
61/** The Session implementation differs between client and server. Still, it is
62 * expected that the Session structure begins with the SessionHeader. This is
63 * the interface that will be used by the SecureChannel. The lifecycle of
64 * Sessions is independent of the underlying SecureChannel. But every Session
65 * can be attached to only one SecureChannel. */
66typedef struct UA_SessionHeader {
69 UA_Boolean serverSession; /* Disambiguate client and server session */
70 UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */
72
73/** For chunked requests */
74typedef struct UA_Chunk {
80 UA_Boolean copied; /* Do the bytes point to a buffer from the network or was
81 * memory allocated for the chunk separately */
83
84typedef SIMPLEQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue;
85
86typedef enum {
88
89 /* Client has sent an OPN, but not received a response so far. */
91
92 /* The server waits for the first request with the new token for the rollover.
93 * The new token is stored in the altSecurityToken. The configured local and
94 * remote symmetric encryption keys are the old ones. */
96
97 /* The client already uses the new token. But he waits for the server to respond
98 * with the new token to complete the rollover. The old token is stored in
99 * altSecurityToken. The local symmetric encryption key is new. The remote
100 * encryption key is the old one. */
103
109
110 /* Rules for revolving the token with a renew OPN request: The client is
111 * allowed to accept messages with the old token until the OPN response has
112 * arrived. The server accepts the old token until one message secured with
113 * the new token has arrived.
114 *
115 * We recognize whether nextSecurityToken contains a valid next token if the
116 * ChannelId is not 0. */
117 UA_ChannelSecurityToken securityToken; /* Also contains the channelId */
118 UA_ChannelSecurityToken altSecurityToken; /* Alternative token for the rollover.
119 * See the renewState. */
120
121 /* The endpoint and context of the channel */
123 void *channelContext; /* For interaction with the security policy */
125
126 /* Asymmetric encryption info */
128 UA_Byte remoteCertificateThumbprint[20]; /* The thumbprint of the remote certificate */
129
130 /* Symmetric encryption nonces. These are used to generate the key material
131 * and must not be reused once the keys are in place.
132 *
133 * Nonces are also used during the CreateSession / ActivateSession
134 * handshake. These are not handled here, as the Session handling can
135 * overlap with a RenewSecureChannel. */
138
141
142 /* Sessions that are bound to the SecureChannel */
144
145 /* If a buffer is received, first all chunks are put into the completeChunks
146 * queue. Then they are processed in order. This ensures that processing
147 * buffers is reentrant with the correct processing order. (This has lead to
148 * problems in the client in the past.) */
149 UA_ChunkQueue completeChunks; /* Received full chunks that have not been
150 * decrypted so far */
151 UA_ChunkQueue decryptedChunks; /* Received chunks that were decrypted but
152 * not processed */
155 UA_ByteString incompleteChunk; /* A half-received chunk (TCP is a
156 * streaming protocol) is stored here */
157
159 UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel,
160 const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
161};
162
164 const UA_ConnectionConfig *config);
165
167
168/** Process the remote configuration in the HEL/ACK handshake. The connection
169 * config is initialized with the local settings. */
172 const UA_TcpAcknowledgeMessage *remoteConfig);
173
176 const UA_SecurityPolicy *securityPolicy,
177 const UA_ByteString *remoteCertificate);
178
179/** Remove (partially) received unprocessed chunks */
180void
182
183/** Wrapper function for generating a local nonce for the supplied channel. Uses
184 * the random generator of the channels security policy to allocate and generate
185 * a nonce with the specified length. */
188
191
194
195
196
199 const void *content, const UA_DataType *contentType);
200
203 UA_MessageType messageType, void *payload,
204 const UA_DataType *payloadType);
205
206/** The MessageContext is forwarded into the encoding layer so that we can send
207 * chunks before continuing to encode. This lets us reuse a fixed chunk-sized
208 * messages buffer. */
223
224/** Start the context of a new symmetric message. */
227 UA_UInt32 requestId, UA_MessageType messageType);
228
229/** Encode the content and send out full chunks. If the return code is good, then
230 * the ChunkInfo contains encoded content that has not been sent. If the return
231 * code is bad, then the ChunkInfo has been cleaned up internally. */
234 const UA_DataType *contentType);
235
236/** Sends a symmetric message already encoded in the context. The context is
237 * cleaned up, also in case of errors. */
240
241/** To be used when a failure occures when a MessageContext is open. Note that
242 * the _encode and _finish methods will clean up internally. _abort can be run
243 * on a MessageContext that has already been cleaned up before. */
244void
246
247
248
250(UA_ProcessMessageCallback)(void *application, UA_SecureChannel *channel,
251 UA_MessageType messageType, UA_UInt32 requestId,
253
254/** Process a received buffer. The callback function is called with the message
255 * body if the message is complete. The message is removed afterwards. Returns
256 * if an irrecoverable error occured.
257 *
258 * Note that only MSG and CLO messages are decrypted. HEL/ACK/OPN/... are
259 * forwarded verbatim to the application. */
263 const UA_ByteString *buffer);
264
265/** Try to receive at least one complete chunk on the connection. This blocks the
266 * current thread up to the given timeout. It will return once the first buffer
267 * has been received (and possibly processed when the message is complete).
268 *
269 * @param channel The SecureChannel
270 * @param application The client or server application
271 * @param callback The function pointer for processing complete messages
272 * @param timeout The timeout (in milliseconds) the method will block at most.
273 * @return Returns UA_STATUSCODE_GOOD or an error code. A timeout does not
274 * create an error. */
276UA_SecureChannel_receive(UA_SecureChannel *channel, void *application,
277 UA_ProcessMessageCallback callback, UA_UInt32 timeout);
278
279/** Internal methods in ua_securechannel_crypto.h */
280
281void
282hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
283 const UA_Byte **buf_end);
284
285/** Decrypt and verify via the signature. The chunk buffer is reused to hold the
286 * decrypted data after the MessageHeader and SecurityHeader. The chunk length
287 * is reduced by the signature, padding and encryption overhead.
288 *
289 * The offset argument points to the start of the encrypted content (beginning
290 * with the SequenceHeader).*/
293 const UA_SecurityPolicyCryptoModule *cryptoModule,
294 UA_MessageType messageType, UA_ByteString *chunk,
295 size_t offset);
296
297size_t
299
301prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
302 const UA_Byte *buf_end, size_t totalLength,
303 size_t securityHeaderLength, UA_UInt32 requestId,
304 size_t *const finalLength);
305
306void
308
311
314 const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
315
316void
318 const UA_Byte *start, UA_Byte **pos);
319
321signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
322 UA_ByteString *buf, size_t securityHeaderLength,
323 size_t totalLength);
324
327 size_t preSigLength, size_t totalLength);
328
329
330
331#define UA_LOG_TRACE_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
332 UA_LOG_TRACE(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
333 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
334 ((CHANNEL)->connection ? (int)((CHANNEL)->connection->sockfd) : 0), \
335 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
336
337#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...) \
338 UA_MACRO_EXPAND(UA_LOG_TRACE_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
339
340#define UA_LOG_DEBUG_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
341 UA_LOG_DEBUG(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
342 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
343 ((CHANNEL)->connection ? (int)((CHANNEL)->connection->sockfd) : 0), \
344 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
345
346#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...) \
347 UA_MACRO_EXPAND(UA_LOG_DEBUG_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
348
349#define UA_LOG_INFO_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
350 UA_LOG_INFO(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
351 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
352 ((CHANNEL)->connection ? (int)((CHANNEL)->connection->sockfd) : 0), \
353 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
354
355#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...) \
356 UA_MACRO_EXPAND(UA_LOG_INFO_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
357
358#define UA_LOG_WARNING_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
359 UA_LOG_WARNING(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
360 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
361 ((CHANNEL)->connection ? (int)((CHANNEL)->connection->sockfd) : 0), \
362 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
363
364#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...) \
365 UA_MACRO_EXPAND(UA_LOG_WARNING_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
366
367#define UA_LOG_ERROR_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
368 UA_LOG_ERROR(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
369 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
370 ((CHANNEL)->connection ? (int)((CHANNEL)->connection->sockfd) : 0), \
371 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
372
373#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...) \
374 UA_MACRO_EXPAND(UA_LOG_ERROR_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
375
376#define UA_LOG_FATAL_CHANNEL_INTERNAL(LOGGER, CHANNEL, MSG, ...) \
377 UA_LOG_FATAL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL, \
378 "Connection %i | SecureChannel %" PRIu32 " | " MSG "%.0s", \
379 ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \
380 (CHANNEL)->securityToken.channelId, __VA_ARGS__)
381
382#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...) \
383 UA_MACRO_EXPAND(UA_LOG_FATAL_CHANNEL_INTERNAL(LOGGER, CHANNEL, __VA_ARGS__, ""))
384
386
387#endif /* UA_SECURECHANNEL_H_ */
UA_SecureChannelState
Definition common.h:120
#define _UA_BEGIN_DECLS
#undef UA_DEBUG_DUMP_PKGS
Definition config.h:89
#define _UA_END_DECLS
Definition config.h:96
#define SIMPLEQ_HEAD(name, type)
For chunked requests.
UA_UInt32 requestId
UA_Boolean copied
UA_MessageType messageType
UA_ChunkType chunkType
UA_ByteString bytes
SIMPLEQ_ENTRY(UA_Chunk) pointers
The MessageContext is forwarded into the encoding layer so that we can send chunks before continuing ...
UA_SecureChannel * channel
UA_ByteString messageBuffer
const UA_Byte * buf_end
UA_ChannelSecurityToken altSecurityToken
UA_ByteString localNonce
UA_ByteString remoteNonce
UA_ByteString remoteCertificate
UA_ByteString incompleteChunk
UA_StatusCode(* processOPNHeader)(void *application, UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader)
UA_UInt32 sendSequenceNumber
UA_SecureChannelRenewState renewState
UA_Connection * connection
UA_ChannelSecurityToken securityToken
UA_Byte remoteCertificateThumbprint[20]
UA_UInt32 receiveSequenceNumber
UA_MessageSecurityMode securityMode
UA_CertificateVerification * certificateVerification
SLIST_HEAD(, UA_SessionHeader) sessions
UA_ChunkQueue completeChunks
UA_ChunkQueue decryptedChunks
UA_SecureChannelState state
const UA_SecurityPolicy * securityPolicy
UA_ConnectionConfig config
Thread-local variables to force failure modes during testing.
UA_SecureChannel * channel
UA_Boolean serverSession
UA_NodeId authenticationToken
SLIST_ENTRY(UA_SessionHeader) next
_UA_BEGIN_DECLS typedef bool UA_Boolean
This Source Code Form is subject to the terms of the Mozilla Public License, v.
Definition types.h:26
uint16_t UA_UInt16
Definition types.h:46
uint32_t UA_UInt32
Definition types.h:56
uint32_t UA_StatusCode
Definition types.h:77
uint8_t UA_Byte
Definition types.h:36
UA_MessageSecurityMode
void UA_SecureChannel_init(UA_SecureChannel *channel, const UA_ConnectionConfig *config)
UA_StatusCode UA_ProcessMessageCallback(void *application, UA_SecureChannel *channel, UA_MessageType messageType, UA_UInt32 requestId, UA_ByteString *message)
void UA_MessageContext_abort(UA_MessageContext *mc)
To be used when a failure occures when a MessageContext is open.
UA_StatusCode UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel)
Wrapper function for generating a local nonce for the supplied channel.
UA_StatusCode UA_MessageContext_finish(UA_MessageContext *mc)
Sends a symmetric message already encoded in the context.
UA_StatusCode UA_SecureChannel_processHELACK(UA_SecureChannel *channel, const UA_TcpAcknowledgeMessage *remoteConfig)
Process the remote configuration in the HEL/ACK handshake.
UA_StatusCode signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, UA_ByteString *buf, size_t securityHeaderLength, size_t totalLength)
void padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm, const UA_Byte *start, UA_Byte **pos)
void hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, const UA_Byte **buf_end)
Internal methods in ua_securechannel_crypto.h.
UA_StatusCode UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel)
UA_StatusCode prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, const UA_Byte *buf_end, size_t totalLength, size_t securityHeaderLength, UA_UInt32 requestId, size_t *const finalLength)
UA_StatusCode checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId)
void setBufPos(UA_MessageContext *mc)
void UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel)
Remove (partially) received unprocessed chunks.
size_t calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel)
UA_StatusCode decryptAndVerifyChunk(const UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cryptoModule, UA_MessageType messageType, UA_ByteString *chunk, size_t offset)
Decrypt and verify via the signature.
UA_StatusCode generateRemoteKeys(const UA_SecureChannel *channel)
UA_StatusCode signAndEncryptSym(UA_MessageContext *messageContext, size_t preSigLength, size_t totalLength)
struct UA_SessionHeader UA_SessionHeader
Thread-local variables to force failure modes during testing.
UA_StatusCode UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 requestId, const void *content, const UA_DataType *contentType)
UA_StatusCode UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel, UA_UInt32 requestId, UA_MessageType messageType)
Start the context of a new symmetric message.
struct UA_Chunk UA_Chunk
For chunked requests.
void UA_SecureChannel_close(UA_SecureChannel *channel)
UA_StatusCode UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId, UA_MessageType messageType, void *payload, const UA_DataType *payloadType)
UA_StatusCode checkAsymHeader(UA_SecureChannel *channel, const UA_AsymmetricAlgorithmSecurityHeader *asymHeader)
UA_StatusCode UA_MessageContext_encode(UA_MessageContext *mc, const void *content, const UA_DataType *contentType)
Encode the content and send out full chunks.
UA_StatusCode UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application, UA_ProcessMessageCallback callback, const UA_ByteString *buffer)
Process a received buffer.
UA_StatusCode UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, const UA_SecurityPolicy *securityPolicy, const UA_ByteString *remoteCertificate)
UA_SecureChannelRenewState
@ UA_SECURECHANNELRENEWSTATE_SENT
@ UA_SECURECHANNELRENEWSTATE_NORMAL
@ UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER
@ UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT
UA_StatusCode UA_SecureChannel_receive(UA_SecureChannel *channel, void *application, UA_ProcessMessageCallback callback, UA_UInt32 timeout)
Try to receive at least one complete chunk on the connection.