/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_ */ |